Repository navigation
fix(server): worktree cleanup no longer deletes files hidden by showUntrackedFiles=no - #15834
Conversation
…iles=no Git refuses to remove a worktree that has untracked files unless forced, but that check honors status.showUntrackedFiles. With it set to no, git status reports new files as clean and `git worktree remove` deletes them, which automatic cleanup does without --force. removeWorktree now runs Git with status.showUntrackedFiles=normal so its own check sees them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused server-side bug fix that makes Git’s non-forced worktree safety check ignore hidden-untracked-file settings, preventing accidental file deletion. The accompanying integration test covers the affected scenario, and no product defaults or static-analysis suppressions are changed. You can add or adjust custom eligibility rules. Learn more. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthrough
ChangesWorktree Removal Check
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to Worktree cleanup now preserves untracked files hidden by repository configuration, while clean removal remains covered. No actionable merge risk remains. Architecture SummaryArchitecture risk: 🔵 Low · up to The change affects 1 system. Changed systems: Architecture concerns Review detailsSystems and components
Before / after behavior
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Comment |
Upstream sync (run on request ahead of a build): 13 commits to f570bd2, including Claude session fixes (pingdotgg#16897, pingdotgg#16287), background subagent work showing while the parent is idle (pingdotgg#16486), inline MCP apps (pingdotgg#16236) and worktree cleanup changes (pingdotgg#14847, pingdotgg#15150, pingdotgg#15834, pingdotgg#14917). The one conflict, ClaudeAdapterV2.ts, was additive: upstream's per-subagent toolCallsFor delete is kept ahead of the fork's Claude task-tools block. The fork's Codex image fixture gains pingdotgg#16236's MCP-app initialize extension. Attached worktrees stay outside every new cleanup path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## What's Changed * fix(web): replace Lineage timers with Stop on hover by @Bil0000 in pingdotgg/t3code#16791 * fix(clients): running subagent cards stay visible after their parent turn settles by @juliusmarminge in pingdotgg/t3code#16878 * feat: MCP apps render and run inline in threads by @juliusmarminge in pingdotgg/t3code#16236 * fix(server): a background Claude subagent's work shows while its parent is idle by @Vantrongs in pingdotgg/t3code#16486 * fix(mobile): hide threads from switched-off environments by @entity in pingdotgg/t3code#16886 * fix(server): a refused Claude turn no longer throws away its session by @SunkenInTime in pingdotgg/t3code#16287 * fix(web): onboarding Continue no longer locks on computers that won't connect by @juliusmarminge in pingdotgg/t3code#16887 * fix(server): worktree cleanup no longer deletes files hidden by showUntrackedFiles=no by @SunkenInTime in pingdotgg/t3code#15834 * fix(server): merged-worktree cleanup removes worktrees after squash merges by @tris203 in pingdotgg/t3code#14847 * fix(server): free worktrees for terminal thread statuses by @ANSHSINGH050404 in pingdotgg/t3code#15150 * fix(server): Windows worktrees with long paths no longer fail or strand by @That1Drifter in pingdotgg/t3code#14917 * fix(server): main typechecks again after a test used renamed helpers by @juliusmarminge in pingdotgg/t3code#16895 * fix(server): Claude prompts no longer hang on a uuid the session already holds by @juliusmarminge in pingdotgg/t3code#16897 ## New Contributors * @Vantrongs made their first contribution in pingdotgg/t3code#16486 * @entity made their first contribution in pingdotgg/t3code#16886 * @ANSHSINGH050404 made their first contribution in pingdotgg/t3code#15150 * @That1Drifter made their first contribution in pingdotgg/t3code#14917 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2774...v0.0.46-nightly.20261007.2787 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261007.2787
## What's Changed * fix(web): replace Lineage timers with Stop on hover by @Bil0000 in pingdotgg/t3code#16791 * fix(clients): running subagent cards stay visible after their parent turn settles by @juliusmarminge in pingdotgg/t3code#16878 * feat: MCP apps render and run inline in threads by @juliusmarminge in pingdotgg/t3code#16236 * fix(server): a background Claude subagent's work shows while its parent is idle by @Vantrongs in pingdotgg/t3code#16486 * fix(mobile): hide threads from switched-off environments by @entity in pingdotgg/t3code#16886 * fix(server): a refused Claude turn no longer throws away its session by @SunkenInTime in pingdotgg/t3code#16287 * fix(web): onboarding Continue no longer locks on computers that won't connect by @juliusmarminge in pingdotgg/t3code#16887 * fix(server): worktree cleanup no longer deletes files hidden by showUntrackedFiles=no by @SunkenInTime in pingdotgg/t3code#15834 * fix(server): merged-worktree cleanup removes worktrees after squash merges by @tris203 in pingdotgg/t3code#14847 * fix(server): free worktrees for terminal thread statuses by @ANSHSINGH050404 in pingdotgg/t3code#15150 * fix(server): Windows worktrees with long paths no longer fail or strand by @That1Drifter in pingdotgg/t3code#14917 * fix(server): main typechecks again after a test used renamed helpers by @juliusmarminge in pingdotgg/t3code#16895 * fix(server): Claude prompts no longer hang on a uuid the session already holds by @juliusmarminge in pingdotgg/t3code#16897 ## New Contributors * @Vantrongs made their first contribution in pingdotgg/t3code#16486 * @entity made their first contribution in pingdotgg/t3code#16886 * @ANSHSINGH050404 made their first contribution in pingdotgg/t3code#15150 * @That1Drifter made their first contribution in pingdotgg/t3code#14917 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2774...v0.0.46-nightly.20261007.2787 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261007.2787
Automatic worktree cleanup deleted an uncommitted file because
git statuswas configured not to show it. With this change Git refuses the removal and the file survives:Problem
git worktree removewithout--forcerefuses a worktree that has untracked files. That check runsgit status, so it honorsstatus.showUntrackedFiles. People set that tonoto speed up status in large repos. Then status reports new files as clean, Git's own check sees nothing, andgit worktree removeexits 0 and deletes them. I checked this with Git 2.55 directly.This hits automatic cleanup, which trusts
git statusbefore removing and callsgit worktree removewithout--force. The web client's own worktree removal already passesforce: true, so it isn't affected either way.Change
removeWorktreerunsgit -c status.showUntrackedFiles=normal worktree remove. The setting reaches Git's internal status check, so Git refuses the removal (exit 128) the same way it does for anyone else with untracked files. Doing it at removal time means a file created after cleanup's own checks is covered too. With--forceGit skips the check, so forced removals behave as before.Cleanup already handles a failed removal. It logs the refusal and keeps the worktree, and the warning names the worktree on each sweep.
Scope and approval
A bug fix, so no prior approval is needed: automatic cleanup deletes uncommitted files that
status.showUntrackedFiles=nohides fromgit status. It changes only the argumentsremoveWorktreepasses togit worktree remove. It was split out of #15434 so each PR fixes one problem.Verification
Live run on a dev server (Windows 11, Git 2.55.0.windows.1), main at 2a45557 with and without only this change. A scratch repo with a remote, a thread in a new worktree,
git config --worktree status.showUntrackedFiles no, and an uncommittednotes.txt. Settings → Storage → "Delete worktrees with deleted threads" on, then the thread deleted from the sidebar.storage cleanup removed worktreeabout 6 s later, and the worktree andnotes.txtwere gone.removeWorktreeloggedgit worktree remove exited with code 128on each sweep, and the worktree andnotes.txtstayed.Tests in
GitVcsDriverCore.test.ts:notes.txtfrom status, checks status reports clean, and asserts thatremoveWorktreefails and the file is intact. It fails without the-cflag and passes with it.args[0] === "worktree"(now matchesworktree removeanywhere in the arguments).apps/server:vp test run src/vcs/GitVcsDriverCore.test.ts -t worktree, 18 passed.tsc --noEmitinapps/server: clean.vp linton the changed files: one existing warning on a line this PR doesn't touch.Not covered: the inactive, merged and unchanged rules currently skip any thread whose last turn completed (#15146, fixed by #15150), so the live run used the delete rule. The fix is in the removal itself, so it applies to every rule.
Split out of #15434, which keeps the change to which ignored files block cleanup.
Claude Opus 5.5 in Claude Code (via T3 Code).
🤖 Generated with Claude Code