standards: squash-merge makes `git branch --merged` useless — use PR state as the worktree/branch cleanup signal
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 7
Description
Problem
Cleaning up a worktree and branch after a PR merges is blocked by a mechanical trap that reads as developer forgetfulness.
Under squash-merge, the merge commit is a brand-new commit with no ancestry link to the branch. So git branch --merged <base> reports every squash-merged branch as not merged. Consequences:
git branch -d <branch>refuses — "not fully merged"git worktree removesucceeds but strands the branch- The only way through is
git branch -D(force), which is indistinguishable in risk from discarding genuinely unmerged work
The safe command is blocked and the unsafe one is the only option available. That is why post-merge cleanup does not happen — not discipline, mechanics.
Evidence
Measured in TimZander/AudioClassifier on 2026-08-05, immediately after merging a PR:
12 worktrees: 10 MERGED PRs, 1 CLOSED PR, 1 OPEN PR
11 of 12 were stale. git branch --merged origin/main listed exactly one branch — main. Every one of the 10 merged branches looked unmerged to git.
That repo's CLAUDE.md already documents worktree creation carefully and mandates "work in a worktree, never the primary checkout" — so this is not a repo lacking discipline. The safety check simply gives the wrong answer for its merge strategy.
The rule to add
Add to standards/CLAUDE.md, near the existing Git Push Safety / Git Hygiene material:
Cleaning up after a merge
git branch --mergedis meaningless under squash-merge. A squash creates a new commit with no
ancestry to the branch, so every merged branch reports as unmerged andgit branch -drefuses it.
Do not read that refusal as "there is unmerged work here."The merge signal is the pull request, not git ancestry:
gh pr list --head <branch> --state all --json number,state --jq '.[0].state'
MERGEDis authoritative. Only then isgit branch -Dcorrect rather than reckless.Do not use "the remote branch is gone" as the signal. It is an inference from the host's
auto-delete-on-merge setting, not proof of merge — and it stays true for a branch someone deleted
by hand. Measured counter-case: an abandoned (CLOSED, never merged) PR's remote branch was still
present, so the heuristic happens to correlate but does not establish anything.Order matters, and check for work first:
git -C <worktree> status --porcelain # must be empty git worktree remove <worktree> # refuses if dirty — do not reach for --force git branch -D <branch> # -D, not -d: see above git worktree pruneNever remove the worktree you are currently inside, and never remove the primary checkout.
Acceptance criteria
-
standards/CLAUDE.mdstates thatgit branch --mergedis unreliable under squash-merge, with the reason - It gives the
gh pr list --headcheck as the authoritative merge signal - It explicitly rejects "remote branch gone" as a substitute, noting it reflects a host setting
- It specifies the dirty check, the removal order, and the never-remove-current / never-remove-primary constraints
- It explains why
-Dis the correct flag here, so the rule does not read as advocating force-delete generally
Notes
Companion issue: a /tidy-worktrees skill to perform this, since a documented manual procedure demonstrably does not get run — the 11 stale worktrees above accumulated in a repo that documents worktree discipline well.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Edit standards/CLAUDE.md near the existing Git Push Safety / Git Hygiene material. Start by reviewing that section and the acceptance criteria, then add the squash-merge explanation, gh pr list check, dirty-worktree safeguards, removal order, and constraints. Done means all five acceptance criteria are explicitly covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, github
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 1/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100