Skip to content

fix: canonicalize resolveLocksRoot's path so it's stable across symlinked cwds - #1

Open
warnes wants to merge 1 commit into
luohoa97:mainfrom
Warnes-Innovations:fix-macos-realpath-mismatch
Open

warnes wants to merge 1 commit into
luohoa97:mainfrom
Warnes-Innovations:fix-macos-realpath-mismatch

Conversation

@warnes

@warnes warnes commented Jul 30, 2026

Copy link
Copy Markdown

resolveLocksRoot's contract is "same real directory in, same string out, regardless of which worktree you call it from." That held for the simple case but broke when the caller's own working directory passes through a symlink: git returns a plain relative common-dir (e.g. .git) when cwd is the repo root, so path.resolve inherits whatever symlink form cwd was already in — but resolving a linked worktree's common dir requires git to internally chase the worktree's .git pointer file back to the shared directory, and in doing so it hands back an already-canonicalized path. On macOS specifically (/tmp, /var/private/...), these two call shapes return different strings for the same real directory, which is exactly the failure mode resolveLocksRoot exists to prevent — just triggered in its own path handling rather than a caller's.

Verified against the actual test suite, not guessed — before this fix:

expected '/private/var/folders/.../main/.git/agents-locks'
received '/var/folders/.../main/.git/agents-locks'

Fix: resolve the final path through fs.realpath before returning it. Updated the two git.test.ts assertions that compared against the raw sandbox path to compare against its realpath instead, so the tests hold regardless of which OS-specific symlink layer the temp dir sits behind.

All 54 existing tests pass, typecheck clean. No new test added — the two adjusted assertions already exercise this exact path via a real git init + git worktree add pair, matching the file's existing convention of testing against real git repos rather than mocks.

…nked cwds

resolveLocksRoot's whole contract is "same real directory in, same string
out, regardless of which worktree you call it from." That held for the
common case but broke when the caller's own working directory passes
through a symlink: git returns a plain relative common-dir (e.g. ".git")
for the simple "cwd is the repo root" case, so path.resolve(cwd, ...)
inherits whatever symlink form cwd was in — but resolving a LINKED
worktree's common dir requires git to internally chase the worktree's
`.git` pointer file back to the shared directory, and doing so it appears
to hand back an already-canonicalized path. On macOS specifically, where
/tmp and /var are symlinks to /private/tmp and /private/var, these two
call shapes returned two different strings for the same real directory —
exactly the case the existing worktree test is meant to guard, and it was
failing before this fix (verified against the actual test suite, not
guessed):

  expected '/private/var/folders/.../main/.git/agents-locks'
  received '/var/folders/.../main/.git/agents-locks'

Fix: resolve the final path through fs.realpath before returning it, so
the canonical form is used unconditionally. Updated both git.test.ts
assertions that compared against the raw (non-canonicalized) sandbox path
to compare against its realpath instead, so the tests hold regardless of
which OS-specific symlink layer the temp dir sits behind.

All 54 existing tests pass; typecheck is clean. No new test added because
the two adjusted assertions already exercise exactly this path (a real
`git init` + `git worktree add` pair, per the file's existing convention
of testing against real git repos rather than mocks).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

1 participant