Repository navigation
fix(server): storage cleanup judges each repository in a multi-repo worktree - #354
Merged
LoganRupe merged 1 commit intoOct 23, 2026
Conversation
…orktree A multi-repo run's container was judged as one repository. When the project root is a repo, cleanup checked only the root worktree, saw no changes (the nested repos are gitignored) and ran git worktree remove on it, deleting the nested worktrees with their uncommitted work. A container without a root repo was never collected. Cleanup now reads the container's layout, runs every check on each repository's worktree against its own default branch and pull request, and removes the container through WorkspaceWorktrees only when all of them pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In the multi-repo fork, storage cleanup could delete uncommitted work. When the project root is itself a repo with the others cloned inside it and gitignored (the layout kieron describes in pingdotgg#7041), a new-worktree run puts the nested worktrees inside the root's worktree. Cleanup only looked at the root: no changes there, no commits beyond
main, so with "Delete unchanged worktrees" (or "Delete worktrees with deleted threads") it rangit worktree removeon the root and tookbackend/with its uncommitted files. A container without a root repo had the opposite problem and was never collected.Change
When a thread's worktree is a multi-repo container, cleanup reads its layout file and runs the existing checks on each repository's worktree: linked worktree, branch, local changes, submodules, its own default branch (so a
developrepo is judged againstdevelop), and its own pull request. The container goes only when every repository passes, throughWorkspaceWorktrees.remove, so nested worktrees are removed first and files the user left in a plain container stay. Keep reasons name the repository, e.g. "Has uncommitted changes (1 file) in backend". Single-repo worktrees go through the same path as before.Under "Delete merged worktrees", a repository the run never committed to counts as done once another repository's PR is merged, otherwise a root repo that never gets commits would block cleanup forever.
Scope and approval
Fork-only fix for a data-loss bug in the multi-repo feature, raised in pingdotgg#7041 (discussion comment 19133258). The upstream bug for hand-nested worktrees, pingdotgg#23866, is separate: without a layout file there is nothing to read, so this doesn't fix it.
Not covered: resuming a thread whose container was cleaned up recreates only the root worktree. Deleting a container by hand already has the same gap; that's a follow-up.
Verification
Four new tests in
storageCleanup.test.ts: root repo with uncommitted work in a nested worktree is kept, each repo is judged against its own default branch (kept with a commit beyonddevelop, removed once it's pushed there), a plain container is removed along with its links, and a plain container with uncommitted work is kept. All four fail onmulti-repo-workspacesand pass here. The rest of the file has 15 failing orphan-report tests that fail identically onmulti-repo-workspaceswithout this change.In the real app, against two dev servers (before and after), each side has a thread created through "New worktree" in a root-repo project with a gitignored
backendclone and an uncommittedbackend/wip.ts. Turning on "Delete unchanged worktrees" removed the container on the old build (Files then can't listbackend, andwip.tsis gone from disk) and kept it on this one with "Has uncommitted changes (1 file) in backend".Before / after video
compare.mp4
Written with Claude Opus 5.5 in Claude Code.