| name | git-worktree-tidy |
| description | Fetch latest from origin, prune remote-tracking refs, delete stale local branches and worktrees, and fast-forward important branches. Use when tidying up a worktree-based repo layout. |
git-worktree-tidy
Routine hygiene for bare-repo + worktree layouts. Fetches origin, prunes
gone branches and orphaned worktrees, and fast-forwards important local
branches.
When to use
User asks to "fetch prune", "clean up stale branches/worktrees", or
"update main/dev to latest" in a worktree-based repo.
Hard Rules
- Verified-merged branches (merged PR + head == tip, step 3a) and clean
worktrees are recoverable interior work: delete them without asking, and
report what was removed.
- At-risk branches and dirty worktrees hold potentially unshipped work: batch
them into the single confirmation in step 5. Never force-delete a dirty
worktree without explicit approval.
- Use
--ff-only when updating branches. If ff-only fails, stop and ask.
- Operate from the
.bare directory (or repo root) for branch/worktree
management commands.
- Never infer "merged/shipped" from
git rev-list origin/main..<branch> or
git merge-base --is-ancestor alone. Squash- and rebase-merges land the
work under a new SHA, so a fully-shipped branch still shows commits "not in
main" and a non-ancestor tip. Verify ship status against the forge's PR
merge state (step 3a) before classifying a gone branch as unmerged.
Workflow
1) Locate the bare root
Determine the bare repo directory:
- If cwd contains
.bare/, use it
- Otherwise:
git rev-parse --git-common-dir
All branch and worktree management commands run from this directory.
2) Fetch + prune
git fetch --prune origin
Report what was pruned (deleted remote-tracking branches, updated refs).
3) Discover stale branches
git branch -vv | grep ': gone]'
Collect branch names whose upstream is gone.
3a) Verify ship status (gone upstream ≠ merged)
A deleted upstream ("gone") does NOT prove the work shipped, and git ancestry
is unreliable here: squash- and rebase-merges land the work under a new SHA, so
a fully-shipped branch still shows commits "not in main" and a non-ancestor tip.
Verify against the forge before deleting — gone-but-unmerged branches are the
only ones that lose real work.
For each gone-upstream branch (GitHub example; substitute your forge CLI):
gh pr list --state all --head <branch> \
--json number,state,mergedAt,mergeCommit \
--jq '.[] | "#\(.number) \(.state) merged=\(.mergedAt // "no")"'
gh pr view <pr> --json commits --jq '.commits[-1].oid'
Classify each gone branch:
- Merged (verified) — a MERGED PR exists AND its head == local tip → shipped,
safe to delete.
- At risk — no merged PR, or the tip has commits dated after the merge
(
git show -s --format=%ci <tip>) → genuine unshipped work. Flag it; do not
delete without explicit approval.
If gh/the forge CLI is unavailable, say so and treat unverifiable branches as
at risk rather than assuming merged.
4) Discover stale worktrees
git worktree list
git worktree prune --dry-run
Cross-reference worktrees against the gone-branch list. Check each stale
worktree for dirty state:
cd <worktree-path> && git status --short
Categorize:
- Clean + gone: safe to remove
- Dirty + gone: flag for user review
- Prunable metadata: orphaned worktree entries (directory already gone)
5) Report, then confirm only the at-risk class
Present a summary table:
Stale worktrees to remove:
<path> (<branch>) [clean]
<path> (<branch>) [dirty — N uncommitted changes]
Stale branches:
<branch> [merged — PR #N, safe to delete]
<branch> [AT RISK — no merged PR / commits after merge; review first]
Prunable worktree metadata:
<entry>
Proceed with the verified-merged branches and clean worktrees immediately —
they are recoverable interior deletions. Batch the at risk branches and
dirty worktrees into one confirmation, with the ship-status evidence in
front of the user; only that class waits.
6) Remove stale worktrees
For each removable worktree:
git worktree remove <name>
If removal fails (dirty), report and skip unless user approved force.
7) Delete stale branches
git branch -D <branch1> <branch2> ...
8) Prune worktree metadata
git worktree prune -v
9) Update important branches
Identify which branches have dedicated worktrees for main, dev, or
other important branches (user may specify). For each:
cd <worktree-path> && git pull --ff-only origin <branch>
If ff-only fails, report the divergence and ask for guidance.
10) Final status
Show a summary: what was removed, what was updated, any items skipped.