Files
orca/src
Neil 0443d42638 fix(git): give WSL-hosted repos one FETCH_HEAD lock lane (#17898)
The fetch lock key is the worktree's resolved common Git directory. On a Windows
host two derivations split one repo into several lanes, so sibling fetches on the
same repo race the FETCH_HEAD write the lock exists to serialize.

- Windows aliases \\wsl$ to \\wsl.localhost and folds the distro name and any
  drvfs tail case-insensitively, so two spellings of one repo produced two keys.
  The finished key now goes through foldWslUncPathCaseInsensitiveParts. This is a
  pure function of the finished key, so equal keys stay equal: it can only merge.
- Under a drive-spelled base, git-in-WSL's `/mnt/c/repo/.git` gitfile and
  commondir pointers are read by path.resolve as the non-existent
  C:\mnt\c\repo\.git. The commondir read then fails and every linked worktree got
  its own dead-end key while the main checkout keyed on C:\repo\.git. Such a
  pointer now goes through toWindowsWslDrivePath.
- realpath and stat take no AbortSignal, so cancelling a fetch still blocked
  behind a hung 9P/UNC lookup. Both are wrapped in waitForPromiseWithSignal. The
  rejection keeps today's synthetic AbortError shape, including when the caller
  aborts with its own reason, because callers classify on error.name.
- The hand-rolled gitfile regex is replaced by the shared
  parseGitdirMarkerPayload, matching git's own read_gitfile_gently.

A WSL UNC base is deliberately excluded from the pointer translation. win32
path.resolve already carries such a base's distro onto a guest-rooted pointer
(\\wsl.localhost\Ubuntu\home\me\wt + /mnt/c/repo/.git ->
\\wsl.localhost\Ubuntu\mnt\c\repo\.git), and a main worktree's `.git` is a
directory with no pointer to translate, so its key stays on that UNC spelling.
Rewriting only the linked worktrees to C:\... would have split one repo across
two lanes - the opposite of the intent. A test now pins that layout.

Direction of every key change, re-derived over a ten-layout matrix that runs both
this code and an emulation of the pre-change derivation under Win32 path rules:
nine layouts either merge or are byte-identical. The fold is merge-only by
construction; the pointer translation's sole delta is C:\mnt\c\X -> C:\X, and
C:\mnt\c\X is derived from bytes that live at C:\X, so it can only join a
worktree to its own common dir. The tenth layout is the one narrowing: the shared
parser accepts `gitdir:` only at offset 0 where the old regex accepted it on any
line, so a `.git` file with a leading blank line falls through to the parent walk
(C:\repo\.git\FETCH_HEAD -> C:\.git\FETCH_HEAD). Nothing can race there - git
2.44 refuses that same file with `fatal: invalid gitfile format`, so no fetch
runs in such a worktree at all. Native Windows repos with no WSL, SSH, relay and
folder workspaces are byte-identical.

hostPath() returns the same node:path submodule Node itself selects, so it is a
no-op on every real host; it exists so the Win32 derivation is testable off
Windows. resolveGitFetchHeadCommand's argument parsing is untouched, and
--git-dir gitfile dereferencing is deliberately not added: it would make N
worktrees of one repo serialize fetches that run in parallel today.
2026-09-01 02:39:17 -07:00
..