Skip to content

fix(worktree): keep worktrees a thread or uncommitted work still uses - #550

Merged
Tryanks merged 1 commit into
mainfrom
fix/worktree-in-use
Sep 28, 2026
Merged

Tryanks merged 1 commit into
mainfrom
fix/worktree-in-use

Conversation

@Tryanks

@Tryanks Tryanks commented Sep 28, 2026

Copy link
Copy Markdown
Owner

Closes #517
Refs #516

Changed behaviour

A fork keeps its source's cwd but deliberately carries no worktree ownership marker. So when the source thread went away, nothing counted the fork as a user of the source's worktree:

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_orphans also receives every session's cwd and keeps any directory one of them lies in.
  • The sweep no longer passes --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 --force makes 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_session itself: the removal runs on smol::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 --check
  • cargo clippy --workspace --all-targets --locked -- -D warnings
  • cargo nextest run --workspace --locked: 948 passed, 5 skipped

Not run locally: iOS/Android/Web checks and cargo machete (CI covers them).

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
@Tryanks
Tryanks merged commit 971bdb2 into main Sep 28, 2026
7 checks passed
@Tryanks
Tryanks deleted the fix/worktree-in-use branch September 28, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Removing a deleted thread's worktree also deletes its forks' working directory

1 participant