Skip to content

Worktree fallback only survives rm -rf, not git worktree remove or prune #22604

Description

@francisrath

The problem

#22473 was fixed by #22474 and shipped in 3.6.3: when the selected linked worktree's directory disappears, Desktop falls back to the main worktree instead of showing the missing-repository screen.

That fallback works only for a bare rm -rf of the worktree directory. It fails for the two most common ways a worktree actually gets deleted — git worktree remove and rm -rf followed by git worktree prune — because both also delete <main>/.git/worktrees/<name>, and recoverMissingWorktree recovers through that directory:

const worktrees = await listWorktreesFromGitDir(repository.gitDir).catch(...)
const mainWorktree = worktrees.find(wt => wt.type === 'main')

repository.gitDir is the worktree's admin dir. Once it's gone, git --git-dir … worktree list has nothing to read, recoverMissingWorktree returns null, and Desktop falls through to _updateRepositoryMissing(repository, true) exactly as before the fix.

Worse, the case that does recover decays on its own. git worktree prune — run directly, or implicitly by other git commands — removes the metadata for a worktree whose directory was already rm -rf'd. A repository that recovered correctly yesterday shows as missing today, with nothing having changed in Desktop.

The recovery path depends on state that git owns and garbage-collects, so it can't be relied on.

Release version

3.6.3

Operating system

macOS 15 (Darwin 25.5.0)

Steps to reproduce the behavior

mkdir ghd-worktree-repro && cd ghd-worktree-repro
git init -b main main-repo
cd main-repo
git commit -qm "Initial commit" --allow-empty
git worktree add -b wt-remove ../wt-remove
  1. Add main-repo in Desktop, then switch the worktree picker onto wt-remove.
  2. In a terminal: git -C main-repo worktree remove --force ../wt-remove
  3. Focus the Desktop window.

Expected: Desktop falls back to the main worktree, as it does for rm -rf.

Actual: Can't find "wt-remove" — It was last seen at …, offering only Locate / Remove.

Variants tested

All on 3.6.3, same repo, Desktop selected onto the worktree at deletion time:

Deletion method .git/worktrees/<name> Result
rm -rf ../wt-rm survives ✅ falls back to main worktree
git worktree remove --force ../wt-remove destroyed ❌ "Can't find this repository"
rm -rf ../wt-prune + git worktree prune destroyed ❌ "Can't find this repository"
rm -rf, then any later git worktree prune destroyed retroactively ❌ previously-recovering repo now shows missing

Suggested fix

Record the main worktree on the Repository record when Desktop switches onto a linked worktree (in switchWorktree), rather than rediscovering it at recovery time. Recovery then reads app-owned state that the deletion cannot destroy, and listWorktreesFromGitDir becomes a fallback for records written before the change rather than the only source.

The existing coverage in app/test/unit/git/worktree-test.ts exercises only the metadata-survives path; the variants above are worth adding as cases.

Additional context

Related: #22473, #22474. Filed separately because that issue is closed and its fix shipped — this is the remaining gap rather than a regression of what was fixed.

A separate worktree-picker bug turned up while testing this: #22605, filed on its own as it's an unrelated code path.

Metadata

Metadata

Assignees

Labels

bugConfirmed bugs or reports that are very likely to be bugshelp wantedIssues marked as ideal for external contributorspriority-2Bug that affects more than a few users in a meaningful way but doesn't prevent core functions

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions