fix(worktree): keep worktrees a thread or uncommitted work still uses - #550
Merged
Merged
Conversation
A fork keeps its source's cwd but deliberately carries no worktree ownership marker, so both the delete dialog and the startup orphan sweep treated the source's worktree as unused once the source was gone. SessionMeta::shares_worktree_with now counts any session whose cwd lies inside the worktree as well as one owning the same branch. The delete dialog and the host both use it, so deleting the source no longer removes the directory its fork works in. The orphan sweep keeps any directory a session's cwd lies in, and no longer forces removal: git refuses to remove a worktree with modified or untracked files, so a worktree kept on delete loses no uncommitted work. A clean kept worktree is still reclaimed; its tcode/<id> branch survives. Recording keep decisions belongs to #530. Closes #517 Refs #516
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.
Closes #517
Refs #516
Changed behaviour
A fork keeps its source's
cwdbut deliberately carries noworktreeownership marker. So when the source thread went away, nothing counted the fork as a user of the source's worktree:git worktree remove --forceon the directory the fork was working in.~/.tcode/worktrees/whose name was not a loaded session id was force-removed. That covered a deleted source's worktree still used by its fork, and every worktree the user chose to keep on delete (Settings → Archived Threads → Delete always keeps). Uncommitted changes were lost; only thetcode/<id>branch survived.What changes:
SessionMeta::shares_worktree_with(core) is the one rule for "another thread works in this worktree": it owns the same branch, or its cwd lies inside the worktree directory. The delete dialog (worktree_orphaned_by_delete) and the host (delete_session) both use it. The host checks every stored session, archived ones included, plus live residents. So even when the client cannot see a sharer (an archived fork), the host keeps the directory and logs why.cleanup_orphansalso receives every session's cwd and keeps any directory one of them lies in.--force. Git refuses to remove a worktree with modified or untracked files, and that path already ends in the existing "leaving possible orphan" skip. So a worktree kept on delete never loses uncommitted work. Explicit removal (worktree::remove, used when the user picks "remove worktree") still forces.#516 stays open: a clean worktree the user kept is still reclaimed by the sweep (nothing is lost; the branch survives). Honouring an explicit keep decision needs host-owned worktree ownership, which is #530.
Test
orphan_cleanup_uses_age_and_ownership_and_leaves_unregistered_directories(services) is extended with two real git worktrees: one that a session's cwd lies in (a deleted source's fork) and one kept on delete with an untracked file. Both must survive an old-enough sweep. Checked red/green: restoring either the old id-only check or--forcemakes it fail.worktree_is_shared_by_a_fork_in_its_cwd_but_not_by_a_sibling_directory(core) pins the rule both callers depend on. A fork or a session in a subdirectory shares the worktree. A sibling directory with the same name prefix, the main checkout, the owner itself, and the fork's view of its source do not. Under the previous branch-only comparison the fork case fails.There is no runtime-level test of
delete_sessionitself: the removal runs onsmol::unblock, so asserting that it didn't happen would need a timed wait. The decision it depends on is the core rule above.Checks run locally (macOS)
cargo fmt --all --checkcargo clippy --workspace --all-targets --locked -- -D warningscargo nextest run --workspace --locked: 948 passed, 5 skippedNot run locally: iOS/Android/Web checks and
cargo machete(CI covers them).