Skip to content

Add prune subcommand - #56

Merged
leogdion merged 1 commit into
release-1.0.3from
55-prune
Aug 25, 2026
Merged

Add prune subcommand#56
leogdion merged 1 commit into
release-1.0.3from
55-prune

Conversation

@leogdion

@leogdion leogdion commented Aug 21, 2026

Copy link
Copy Markdown
Member

Implements git trees prune [--dry-run]. Closes #55.

What it does

When a user deletes a worktree directory by hand (rm -rf feature-x) instead of using git trees rm, git's administrative entry under $GIT_COMMON_DIR/worktrees/<name>/ lingers. The stale entry keeps showing up in git worktree list and holds the branch locked against a fresh checkout. prune clears those entries.

Stale worktree names go to stdout, one per line (machine-consumable); git's reason for each goes to stderr. Nothing to prune prints a notice on stderr, empty stdout, exit 0.

The --apply exemption — read this part

AGENTS.md carried this rule:

Nothing destructive without --apply. rm and clean report by default and modify state only when --apply is explicitly passed.

prune deliberately does not follow it. It acts immediately, with --dry-run as the only flag. The reasoning:

  • It removes only metadata$GIT_COMMON_DIR/worktrees/<name>/ — for directories that are already gone from disk.
  • A directory still present on disk is never a candidate. Verified by test: a live worktree survives a prune untouched.
  • The branch a pruned worktree held survives. Verified by test: git show-ref --verify --quiet refs/heads/<name> still succeeds after the real run.

There is no work to lose. Inverting this to --apply would make the common case a no-op that prints a nag.

Accordingly I amended AGENTS.md: the rule is now scoped to operations that can lose work ("Nothing that can lose work without --apply."), with prune named as the deliberate exception. There is also an in-code comment on cmd_prune explaining the exemption, so a reviewer scanning AGENTS.md does not read it as a rule violation.

cmd_clean deliberately unmodified

cmd_clean already calls git worktree prune internally after each removal and again at the end. It needs no prune flag, and this PR does not touch it.

Implementation notes

  • The report is captured before acting. The list then survives a real prune that fails partway, and it is the only way to report accurately under --dry-run.
  • 2>&1 is required. git worktree prune --verbose writes its report to stderr, not stdout (verified on git 2.54) — out=$(git worktree prune -n -v) captures nothing.
  • Whole-line regex, not $2. A field split would truncate a worktree name containing a space.
  • --expire is not exposed, keeping the surface minimal.

Also updated

Header docblock, usage() heredoc, main() dispatch arm, and a README section with the acts-immediately callout.

Verification

bash -n git-trees && bash -n install.sh && bash -n tests/smoke.sh   # clean
shellcheck -s bash git-trees install.sh tests/smoke.sh              # clean (0.11.0)
tests/smoke.sh ./git-trees                                          # 220 assertions, 0 failures, exit 0

New # --- prune --- test section, placed before # --- clean --- since clean must stay last (its fixtures mutate the shared $ORIGIN). The prune fixtures work entirely inside their own new_container prune-c and do not mutate $ORIGIN. Coverage: clean container (empty stdout, exit 0); a worktree whose directory is rm -rf'd behind git's back; --dry-run naming it while leaving metadata intact; the real run removing metadata but leaving the branch; idempotence; a live worktree never pruned; unknown option, positional arg, and outside-a-repo all rejected.

🤖 Generated with Claude Code


Release coordination (v1.0.3)

One of five PRs into release-1.0.3 (#56 prune, #58 sync, #60 completions, #59 curl install, #57 Homebrew). All five are green on CI (smoke on Linux + macOS).

Suggested merge order: #56#58#60#59#57. Only one pair conflicts: #58 vs #56.

Merge first. #58 (sync) will then need a rebase: both PRs append to the same two spots in tests/smoke.sh (the help lists … assertion block and the new-section insertion point before # --- clean ---). Two trivial adjacent-append conflicts; git-trees and README.md merge cleanly.

Note: CodeRabbit skipped all five — "reviews are disabled for this base branch." These have not had automated review; that would come when release-1.0.3 merges to main.

The CHANGELOG is deliberately excluded from every PR — it needs the merged PR URLs, so it lands as one commit on release-1.0.3 before tagging v1.0.3.

Surfaces `git worktree prune` as a user-facing command. When a worktree
directory is deleted by hand (`rm -rf feature-x`) instead of through
`git trees rm`, git's administrative entry lingers in `git worktree list`
and keeps the branch locked against a fresh checkout.

`prune` acts immediately with only a `--dry-run` preview, deliberately
exempt from the `--apply` rule: it unlinks metadata only for directories
already gone from disk, and leaves the branch untouched, so there is no
work to lose. AGENTS.md is amended to scope that rule to operations that
can lose work and to name prune as the exception.

The report is captured before acting, from stderr (`git worktree prune
--verbose` writes there, not stdout), and parsed with a whole-line regex
so a name containing a space is not truncated by field splitting.

`cmd_clean` is left unmodified — it already prunes internally.

Closes #55

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c310ee5a-5359-4006-bd56-af72a37cde89

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@leogdion
leogdion merged commit fa00cde into release-1.0.3 Aug 25, 2026
4 checks passed
@leogdion
leogdion deleted the 55-prune branch August 25, 2026 20:03
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.

1 participant