anthropics / anthropics/claude-code
Archiving a desktop session never deletes its worktree when the PR was squash-merged
- Vorherrschende Sprache
- Python
- Sterne
- 145k
- Forks
- 23.1k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
## Environment
- Claude Code 2.1.260, desktop app 1.46388.1 (macOS, Code tab)
- Worktree root configured outside the repo; also reproduces with the default in-repo location
## Expected
Per the docs, archiving a session removes its worktree ("To remove a worktree when you're done, hover over the session in the sidebar and click the archive icon").
## Actual
For repos where PRs are squash-merged (our org default, and GitHub's most common merge strategy), the worktree survives archiving in practically every case. Over weeks this accumulated ~25 leftover worktrees / ~13 GB (each carries its own node_modules and build output).
## Root cause (from inspecting local state)
Cleanup appears to run a safety check equivalent to "branch has commits not on the default branch". Squash-merging rewrites history, so the session branch always looks unmerged by commit ancestry, and the check keeps the worktree, even though:
- the PR is merged (the app itself shows prState MERGED on the session), and
- the branch's upstream is deleted, i.e. `git branch -v` shows `[gone]` after `git fetch --prune`.
Example from `git-worktrees.json` + on disk: an archived session's worktree remained with its branch at 2 commits "ahead" of main that are all contained in a squash-merge commit. Worktrees whose branches happened to be ancestry-merged were correctly deleted, confirming the cleanup path itself works.
## Consequences
- The documented archive behavior effectively never fires for squash-merge workflows.
- The untracked-dir GC does not help either: leftover worktrees stay leased/protected and get recycled into new sessions, which refreshes their protection indefinitely.
- New sessions silently reuse the stale directories (fine per se, but it masks the leak and the sidebar briefly shows a different worktree name than the one actually leased, which is confusing).
## Suggested fix
When deciding whether a worktree is safe to delete, treat the branch as merged if any of:
1. The session's tracked PR state is MERGED (the app already has this signal), or
2. The branch's upstream is gone after a pruning fetch (the standard squash-merge heuristic), or
3. Commit ancestry says merged (current check).
Uncommitted/untracked changes should of course still block deletion.
## Repro
1. In a repo whose PRs are squash-merged, start a desktop session in a worktree, commit, push, open a PR.
2. Squash-merge the PR (remote branch deleted).
3. Archive the session.
4. The worktree directory and local branch remain; `git log main..` shows the squashed commits, `git branch -v` shows `[gone]`.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Rechercherichtung
Trace the archive cleanup safety check and its handling of the session's prState MERGED and deleted upstream, using git-worktrees.json and the git branch -v/fetch --prune state from the reproduction. Reproduce a squash-merged session, then verify that archiving removes its worktree while uncommitted or untracked changes still block deletion.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- git, python
- Bereich
- desktop-dev, devtools
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 68/100