Problem
The worktree cleanup safety check can miss local-only commits and delete the only branch reference that reaches them.
create_worktree() creates wt/<name> with:
git worktree add <path> -b wt/<name> HEAD
The new branch has no upstream by default. However, _count_worktree_changes() counts commits with:
git log @{push}..HEAD --oneline
For a newly-created worktree branch this command exits with status 128 and writes no stdout:
fatal: no upstream configured for branch 'wt/demo'
The helper does not check either Git command's return code, so the empty stdout is interpreted as zero commits. A clean worktree containing a local commit can therefore pass the safety check. remove_worktree() then runs git worktree remove --force followed by git branch -D wt/<name>.
This affects:
s18_worktree_isolation/code.py
s19_mcp_plugin/code.py
s20_comprehensive/code.py
Reproduction
push_log_rc=128
computed_commits=0
actual_local_only_commits=1
worktree_clean=yes
error=fatal: no upstream configured for branch 'wt/demo'
Expected behavior
Cleanup without discard_changes=true should refuse when:
- the worktree has uncommitted files;
- the worktree branch contains commits not reachable from the main worktree's current
HEAD; or
- any Git status/history check fails.
Using the main worktree's HEAD as the reachability baseline avoids relying on an upstream that temporary worktree branches do not have. Error paths should fail closed.
Suggested coverage
- Clean worktree with no unique commits can be removed.
- Worktree with uncommitted files is preserved.
- Clean worktree with no upstream and a unique commit is preserved.
- Git status/history verification failures preserve the worktree.
This is not additional production hardening: it restores the safety behavior described in the s18 cleanup section, which says removal refuses by default when changes exist.
AI assistance was used to reproduce and analyze this issue; I reviewed and verified the report.
Problem
The worktree cleanup safety check can miss local-only commits and delete the only branch reference that reaches them.
create_worktree()createswt/<name>with:The new branch has no upstream by default. However,
_count_worktree_changes()counts commits with:For a newly-created worktree branch this command exits with status 128 and writes no stdout:
The helper does not check either Git command's return code, so the empty stdout is interpreted as zero commits. A clean worktree containing a local commit can therefore pass the safety check.
remove_worktree()then runsgit worktree remove --forcefollowed bygit branch -D wt/<name>.This affects:
s18_worktree_isolation/code.pys19_mcp_plugin/code.pys20_comprehensive/code.pyReproduction
Expected behavior
Cleanup without
discard_changes=trueshould refuse when:HEAD; orUsing the main worktree's
HEADas the reachability baseline avoids relying on an upstream that temporary worktree branches do not have. Error paths should fail closed.Suggested coverage
This is not additional production hardening: it restores the safety behavior described in the s18 cleanup section, which says removal refuses by default when changes exist.
AI assistance was used to reproduce and analyze this issue; I reviewed and verified the report.