Skip to content

feat(clean): add --to filter for git gtr clean --merged#167

Merged
helizaga merged 8 commits intocoderabbitai:mainfrom
scarf005:feat/clean-merged-target
Apr 27, 2026
Merged

feat(clean): add --to filter for git gtr clean --merged#167
helizaga merged 8 commits intocoderabbitai:mainfrom
scarf005:feat/clean-merged-target

Conversation

@scarf005
Copy link
Copy Markdown
Contributor

@scarf005 scarf005 commented Apr 10, 2026

Pull Request

Description

Adds --to <Ref> option to git gtr clean --merged and tightens merged cleanup so only worktrees whose current branch tip matches a merged PR/MR for the requested target ref are considered.

Motivation

For teams that merge PRs into staging or release branches before main, git gtr clean --merged --to main must not treat staging-only merges as eligible for deletion. This also needs to avoid false positives when branch names are reused.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Other (please describe):

Testing

  • bats tests/cmd_clean.bats tests/provider.bats tests/cmd_help.bats tests/completion.bats
  • shellcheck lib/commands/clean.sh lib/provider.sh lib/commands/help.sh
  • ./bin/gtr clean
  • git gtr clean
  • ./scripts/generate-completions.sh --check

Manual Testing Checklist

Tested on:

  • macOS
  • Linux (specify distro: __)
  • Windows (Git Bash)

Core functionality tested:

  • git gtr new <branch> - Create worktree
  • git gtr go <branch> - Navigate to worktree
  • git gtr editor <branch> - Open in editor (if applicable)
  • git gtr ai <branch> - Start AI tool (if applicable)
  • git gtr rm <branch> - Remove worktree
  • git gtr list - List worktrees
  • git gtr config - Configuration commands (if applicable)
  • Other commands affected by this change: git gtr clean --merged --to <ref>

Test Steps

  1. Create a worktree and commit on the feature branch.
  2. Open a PR targeting a non-main branch such as dummy.
  3. Run git gtr clean --merged --to main.
  4. Verify the worktree is not removed because the PR was not merged into main.
  5. Reuse a previously merged branch name and verify cleanup only matches the current branch tip.

Expected behavior:
Only worktrees whose current branch tip belongs to a merged PR/MR into the specified target ref are removed.

Actual behavior:
git gtr clean --merged --to main ignores non-merged worktrees, rejects --to without --merged, and does not emit dirty-skip warnings for branches that were never eligible for deletion.

Breaking Changes

  • This PR introduces breaking changes
  • I have discussed this in an issue first
  • Migration guide is included in documentation

Checklist

Before submitting this PR, please check:

  • I have read CONTRIBUTING.md
  • My code follows the project's style guidelines
  • I have performed manual testing on at least one platform
  • I have updated documentation (README.md, CLAUDE.md, etc.) if needed
  • My changes work on multiple platforms (or I've noted platform-specific behavior)
  • I have added/updated shell completions (if adding new commands or flags)
  • I have tested with both git gtr (production) and ./bin/gtr (development)
  • No new external dependencies are introduced (Bash + git only)
  • All existing functionality still works

Additional Context

This also fixes the completion generator so regenerated bash/zsh/fish completions keep the --to option.


License Acknowledgment

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache License 2.0.

Summary by CodeRabbit

  • New Features

    • Added --to for git gtr clean --merged to restrict cleanup to worktrees whose PRs/MRs were merged into the specified base ref; --to is only valid with --merged.
  • Documentation

    • Updated README and command help with --to usage and an example (git gtr clean --merged --to main).
  • Shell Completions

    • Added --to completion support for Bash, Zsh, and Fish.
  • Tests

    • Added tests for --to validation, merged-check behavior, and related edge cases.

Assisted-by: gpt-5.4-high on opencode
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@scarf005 scarf005 requested a review from NatoBoram as a code owner April 10, 2026 04:52
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4bf5933a-c9ff-41ff-896e-9cf9a4ef546f

📥 Commits

Reviewing files that changed from the base of the PR and between 33bf641 and 57c8291.

📒 Files selected for processing (1)
  • lib/provider.sh

Walkthrough

Adds a --to <ref> option to git gtr clean --merged, plumbing it through CLI parsing, completions, help/docs, merged-clean logic, provider queries (GitHub/GitLab), and tests to only remove worktrees whose PRs/MRs were merged into the specified ref.

Changes

Cohort / File(s) Summary
Documentation & Help
README.md, lib/commands/help.sh
Document new --to <ref> flag and add git gtr clean --merged --to main usage example in command and full help text.
Shell completions & generator
completions/_git-gtr, completions/git-gtr.fish, completions/gtr.bash, scripts/generate-completions.sh
Add --to option to Zsh (:ref:), Fish (-r), and Bash completion outputs; update completion generator to emit the new option.
Clean command logic
lib/commands/clean.sh
Add --to CLI arg (error if used without --merged), propagate target_ref into _clean_merged, compute branch_tip (git rev-parse HEAD), and call check_branch_merged with target_ref and branch_tip.
Provider detection & helpers
lib/provider.sh
Add normalize_target_ref and change check_branch_merged signature to accept [target_ref] [branch_tip]; update GitHub/GitLab queries to filter by base/target and to match head commit when branch_tip supplied.
Tests
tests/cmd_clean.bats, tests/cmd_help.bats, tests/provider.bats
Add tests for --to validation and behavior, ensure provider stubs receive branch-tip arg, validate normalized base/target filtering and SHA matching, and update help-output expectations.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as cmd_clean
    participant Cleaner as _clean_merged
    participant ProviderCheck as check_branch_merged
    participant Provider as GitHub/GitLab

    User->>CLI: git gtr clean --merged --to main
    CLI->>CLI: parse flags -> merged=true, target_ref="main"
    CLI->>Cleaner: _clean_merged(target_ref="main")
    Cleaner->>Cleaner: for each worktree: determine branch, branch_tip
    Cleaner->>ProviderCheck: check_branch_merged(provider, branch, "main", branch_tip)
    ProviderCheck->>Provider: query PRs/MRs filtered by base/target="main" and head==branch_tip
    Provider-->>ProviderCheck: return matches
    ProviderCheck-->>Cleaner: merged? yes/no
    Cleaner->>Cleaner: remove only worktrees merged into "main"
    Cleaner-->>User: report cleanup results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibble refs and chase each tip,

"--to main" guides my tidy skip,
I sniff the merge and match the SHA,
Pull out the twigs that got swept away,
Hop — burrow neat, commit day.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(clean): add --to filter for git gtr clean --merged' accurately and concisely summarizes the main feature addition, clearly indicating a new filter option for the clean command.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/cmd_clean.bats (1)

147-159: Strengthen this test with a non-matching target branch assertion.

Current test validates the positive path. Add a second worktree that should not be removed to lock in filter behavior and prevent false positives.

Suggested test hardening
 `@test` "cmd_clean --merged --to filters by target ref" {
   create_test_worktree "merged-to-main"
+  create_test_worktree "merged-to-develop"

   _clean_detect_provider() { printf "github"; }
   ensure_provider_cli() { return 0; }
-  check_branch_merged() { [ "$2" = "merged-to-main" ] && [ "$3" = "main" ]; }
+  check_branch_merged() {
+    [ "$3" = "main" ] && [ "$2" = "merged-to-main" ]
+  }
   run_hooks_in() { return 0; }
   run_hooks() { return 0; }

   run cmd_clean --merged --to main --yes
   [ "$status" -eq 0 ]
   [ ! -d "$TEST_WORKTREES_DIR/merged-to-main" ]
+  [ -d "$TEST_WORKTREES_DIR/merged-to-develop" ]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cmd_clean.bats` around lines 147 - 159, The test "cmd_clean --merged
--to filters by target ref" currently only verifies removal of the matching
worktree; add a second non-matching worktree (e.g., create_test_worktree
"merged-to-feature") and stub the same helpers (_clean_detect_provider,
ensure_provider_cli, check_branch_merged, run_hooks_in, run_hooks) so that
check_branch_merged returns true only for branch "merged-to-main" -> "main" and
false for the non-matching pair, then after running run cmd_clean --merged --to
main --yes assert status is 0, assert the "merged-to-main" directory was removed
and assert the "merged-to-feature" directory still exists to lock in the
negative case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@completions/_git-gtr`:
- Around line 82-84: The completions for the new flags (--merged, --to, --yes)
are stale; re-run the project's completion-generation script/tool to regenerate
shell completions for the gtr command, ensure the generated artifacts for all
three completion targets (gtr.bash, _git-gtr, git-gtr.fish) include the new
flags/options, and commit those regenerated files together in the same change so
CI no longer reports stale completions.

In `@lib/commands/clean.sh`:
- Around line 149-157: After parsing args in lib/commands/clean.sh, validate
that --to (_arg_to -> target_ref) is only used when --merged (_arg_merged ->
merged_mode) is enabled: if target_ref is non-empty and merged_mode is false/0,
print a clear error message and exit non-zero; implement this check near where
merged_mode and target_ref are set (after parse_args) so the script rejects the
unsupported combination early rather than silently ignoring --to.

---

Nitpick comments:
In `@tests/cmd_clean.bats`:
- Around line 147-159: The test "cmd_clean --merged --to filters by target ref"
currently only verifies removal of the matching worktree; add a second
non-matching worktree (e.g., create_test_worktree "merged-to-feature") and stub
the same helpers (_clean_detect_provider, ensure_provider_cli,
check_branch_merged, run_hooks_in, run_hooks) so that check_branch_merged
returns true only for branch "merged-to-main" -> "main" and false for the
non-matching pair, then after running run cmd_clean --merged --to main --yes
assert status is 0, assert the "merged-to-main" directory was removed and assert
the "merged-to-feature" directory still exists to lock in the negative case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4910c592-4cf8-4508-9cbc-4c8b29a846d6

📥 Commits

Reviewing files that changed from the base of the PR and between 025de7f and 6f39450.

📒 Files selected for processing (10)
  • README.md
  • completions/_git-gtr
  • completions/git-gtr.fish
  • completions/gtr.bash
  • lib/commands/clean.sh
  • lib/commands/help.sh
  • lib/provider.sh
  • tests/cmd_clean.bats
  • tests/cmd_help.bats
  • tests/provider.bats

Comment thread completions/_git-gtr
Comment thread lib/commands/clean.sh
scarf005 and others added 2 commits April 10, 2026 14:16
Avoid dirty skip noise for non-merged worktrees and reject --to without --merged.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/provider.sh`:
- Around line 116-124: The pr_matches logic in lib/provider.sh uses gh pr list
and glab mr list but only inspects the first page, causing false negatives for
reused branch names; update each gh pr list call that assigns pr_matches (the
blocks referencing pr_matches and branch_tip) to include a sufficiently large
--limit (or use --all) and implement pagination (or loop) so all pages are
examined, and likewise change glab mr list invocations to use --all or a paging
loop; ensure the selection/filtering (the jq/map/select parts relying on
headRefOid and state) remains the same so the code still counts merged PRs/MRs
but across the complete result set.
- Around line 114-118: Normalize the target_ref variable to a plain branch name
before passing it to provider filters: detect and strip refs/heads/ and remote
prefixes (e.g., origin/) or resolve via git rev-parse --abbrev-ref to obtain the
simple branch name, then use that normalized variable in the gh pr list calls
(the target_ref used with --base and the branch_tip comparison) and in the glab
--target-branch usage mentioned around the later block (lines near the other
gh/glab calls). Ensure normalization happens once right after parsing --to and
before any use in the pr/MR queries so callers can still pass refs like
refs/heads/main or origin/main safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0dd3a9e3-9de4-4594-925f-765a49904572

📥 Commits

Reviewing files that changed from the base of the PR and between c06bdd8 and 0d7f148.

📒 Files selected for processing (2)
  • lib/provider.sh
  • tests/provider.bats
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/provider.bats

Comment thread lib/provider.sh Outdated
Comment thread lib/provider.sh Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lib/provider.sh (1)

151-163: Remove redundant conditional—both branches execute identical logic.

The outer if [ -n "$normalized_target_ref" ] check is unnecessary here because the --base flag was already conditionally added in lines 148-150. Both the then (lines 152-156) and else (lines 158-162) branches contain identical code.

♻️ Proposed simplification
       if [ -n "$normalized_target_ref" ]; then
         gh_args+=(--base "$normalized_target_ref")
       fi
-      if [ -n "$normalized_target_ref" ]; then
-        if [ -n "$branch_tip" ]; then
-          pr_matches=$(gh "${gh_args[@]}" --json state,headRefOid --jq "map(select(.state == \"MERGED\" and .headRefOid == \"$branch_tip\")) | length" 2>/dev/null || true)
-        else
-          pr_matches=$(gh "${gh_args[@]}" --json state --jq 'map(select(.state == "MERGED")) | length' 2>/dev/null || true)
-        fi
+      if [ -n "$branch_tip" ]; then
+        pr_matches=$(gh "${gh_args[@]}" --json state,headRefOid --jq "map(select(.state == \"MERGED\" and .headRefOid == \"$branch_tip\")) | length" 2>/dev/null || true)
       else
-        if [ -n "$branch_tip" ]; then
-          pr_matches=$(gh "${gh_args[@]}" --json state,headRefOid --jq "map(select(.state == \"MERGED\" and .headRefOid == \"$branch_tip\")) | length" 2>/dev/null || true)
-        else
-          pr_matches=$(gh "${gh_args[@]}" --json state --jq 'map(select(.state == "MERGED")) | length' 2>/dev/null || true)
-        fi
+        pr_matches=$(gh "${gh_args[@]}" --json state --jq 'map(select(.state == "MERGED")) | length' 2>/dev/null || true)
       fi
       [ "${pr_matches:-0}" -gt 0 ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/provider.sh` around lines 151 - 163, The outer conditional checking
normalized_target_ref is redundant because the --base flag is already handled
earlier; simplify by removing that outer if/else and keep a single branch that
sets pr_matches based on whether branch_tip is set: use gh with --json
state,headRefOid and the jq filter for MERGED+headRefOid when branch_tip is
non-empty, otherwise use gh with --json state and the jq filter for MERGED;
update references to pr_matches, gh_args, branch_tip and remove the duplicate
blocks around normalized_target_ref.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/provider.sh`:
- Around line 151-163: The outer conditional checking normalized_target_ref is
redundant because the --base flag is already handled earlier; simplify by
removing that outer if/else and keep a single branch that sets pr_matches based
on whether branch_tip is set: use gh with --json state,headRefOid and the jq
filter for MERGED+headRefOid when branch_tip is non-empty, otherwise use gh with
--json state and the jq filter for MERGED; update references to pr_matches,
gh_args, branch_tip and remove the duplicate blocks around
normalized_target_ref.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 201cdbb7-1db7-49ed-a7d1-9bc84a0062cf

📥 Commits

Reviewing files that changed from the base of the PR and between 0d7f148 and a26a3ae.

📒 Files selected for processing (2)
  • lib/provider.sh
  • tests/provider.bats
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/provider.bats

@scarf005
Copy link
Copy Markdown
Contributor Author

@helizaga hi, would there be anything left for me to fix? thanks!

@helizaga helizaga merged commit b8ca496 into coderabbitai:main Apr 27, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants