anthropics / anthropics/claude-plugins-official
commit-commands: /clean_gone can force-delete healthy branches and destroy uncommitted worktrees
- Vorherrschende Sprache
- Python
- Sterne
- 36.2k
- Forks
- 4.1k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
`plugins/commit-commands/commands/clean_gone.md` selects branches by grepping `git branch -v` output for `[gone]`, then force-deletes them and force-removes any attached worktree. Two of those steps can destroy work. Both reproduce from a clean repo.
### 1. A commit message containing `[gone]` gets an unrelated branch force-deleted
The grep matches anywhere in the line, including the subject:
```bash
git init -b main repro && cd repro
git commit --allow-empty -m base
git remote add origin ../remote.git # any reachable remote
git push -u origin main
git checkout -b innocent
git commit --allow-empty -m "fix: handle [gone] upstreams"
git push -u origin innocent
git checkout main
# the selector from step 3, verbatim:
git branch -v | grep '\[gone\]' | sed 's/^[+* ]//' | awk '{print $1}'
# -> innocent
```
`innocent` has a healthy upstream and is queued for `git branch -D`. If it holds unpushed commits, they go with it.
### 2. `git worktree remove --force` destroys uncommitted work
Step 3 runs `--force` unconditionally. With one worktree per concurrent agent session — which the plugin's own `/commit-push-pr` workflow encourages — a stale branch in one session silently wipes another session's working tree:
```bash
git worktree add wt some-branch
echo "not committed yet" > wt/IMPORTANT.txt
git worktree remove wt
# fatal: 'wt' contains modified or untracked files, use --force to delete it <- git's own guard
git worktree remove --force wt
# succeeds; IMPORTANT.txt is gone
```
Git refuses by default here for exactly this reason; `--force` opts out of that protection with nothing put in its place.
### 3. No `git fetch --prune`, so the command often reports nothing to do
Nothing is marked gone until a pruning fetch has run, so on a repo whose remote branches were deleted elsewhere (the normal case after a squash-merge) the command finds nothing and reports success.
### 4. `-v` and `-vv` print different text
Worth noting for anyone editing this file: `git branch -v` prints a bare `[gone]`, while `-vv` prints `[origin/: gone]`. The current pattern is correct for `-v` only — adding a `v` for more context silently makes it match nothing, and the command then reports "no cleanup needed" forever.
### Suggested fix
Read the gone set from plumbing instead of parsing porcelain. `%(upstream:track)` is exactly `[gone]`, in a field of its own, under every verbosity:
```bash
git fetch --prune
git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads |
awk '$2=="[gone]"{print $1}' | while read branch; do
worktree=$(git worktree list | grep -F "[$branch]" | awk '{print $1}')
if [ -n "$worktree" ] && [ "$worktree" != "$(git rev-parse --show-toplevel)" ]; then
# no --force: a worktree holding uncommitted work must refuse
if ! git worktree remove "$worktree"; then
echo "SKIPPING $branch - its worktree has uncommitted changes or is in use"
continue
fi
fi
git branch -D "$branch"
done
```
That fixes 1-4 together: no prefix to strip, no subject-line false positives, no `-v`/`-vv` trap, and a worktree with live work is skipped with a message rather than deleted.
One thing the docs could add regardless of the code: "gone" usually means squash-merged, but it also covers a branch someone deleted unmerged. Since the next step is `git branch -D`, it is worth accounting for each branch's work (a merged PR, or an ancestor of the default branch) before deleting.
I understand this repo only accepts PRs from Anthropic team members, so I am filing this as an issue rather than a patch.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Bewertung
Dieses Issue wurde noch nicht bewertet.