fix(git): Windows drive-letter paths and worktree reuse in ensure_worktree (swamp-club #3521) #510

Merged
stack72 merged 2 commits from 3521 into main 2026-10-16 22:21:45 +00:00
Owner

Fixes swamp-club #3521.

Problem

@swamp/git handled worktree and local-remote paths as POSIX strings. On Windows:

  1. ensure_worktree with path: C:/repos/factory/work/ITEM treated the drive-letter path as relative and created the worktree under <cwd>/C:/....
  2. Re-running ensure_worktree for an existing worktree failed with <path> is outside the worktree root <root>: once the directory existed, realPathSync returned a backslash path that never matched the forward-slash root prefix.
  3. The primary-checkout, git-directory and overlap safety checks never matched git's C:/... listing, so they were effectively off.

Fix

  • New git/extensions/models/_lib/paths.ts: absolutePath, canonicalPath, samePath, isWithin, built on @std/path/windows on Windows. Drive-letter, backslash and drive-less paths resolve correctly, and every comparison folds case and separator. The platform rules are injectable (setPathFlavor), so the Windows behaviour is tested on macOS/Linux.
  • operations.ts: every worktree path comparison and current-directory base goes through the new module. That covers ensure_worktree, verify_worktree, remove_worktree, readLayout, the requireCleanPrimary nested filter and the ensure_checkout top-level check.
  • POSIX behaviour is unchanged. absolutePath keeps the previous join, so .. is still resolved by the kernel.
  • normaliseRemote on Windows no longer reads C:/repo as an scp-style host c. file:///C:/... decodes to a Windows path, and a malformed escape is kept as-is, as on POSIX.
  • The .. guard on worktree path/root also splits on backslashes (a\..\b).

Testing

  • paths_test.ts: the issue's exact canonicalPath cases with cwd C:\repos\factory, the reuse root check, separator/case folding, \\?\ prefix, drive root, symlinked ancestor, UNC, plus POSIX tests that pin the current behaviour.
  • git_test.ts: Windows normaliseRemote, rejection of a backslash .., readLayout + assertPlacement over a mocked C:/ worktree list (reuse passes, the safety checks still refuse), and remove_worktree across spellings.
  • 266 tests pass, and all existing real-git worktree tests are unchanged. Disabling the Windows case/separator folding fails 5 of the new tests.
  • verify-build and verify-reviews passed on 7280d23; the attestation is posted.

Caveat: there is no Windows CI runner, so Windows behaviour is exercised only through the injected Windows rules. We'll ask the reporter to confirm on Windows 11 after release.

Manifest bumped to 2026.10.16.1.

🤖 Generated with Claude Code

Fixes swamp-club #3521. ## Problem `@swamp/git` handled worktree and local-remote paths as POSIX strings. On Windows: 1. `ensure_worktree` with `path: C:/repos/factory/work/ITEM` treated the drive-letter path as relative and created the worktree under `<cwd>/C:/...`. 2. Re-running `ensure_worktree` for an existing worktree failed with `<path> is outside the worktree root <root>`: once the directory existed, `realPathSync` returned a backslash path that never matched the forward-slash root prefix. 3. The primary-checkout, git-directory and overlap safety checks never matched git's `C:/...` listing, so they were effectively off. ## Fix - New `git/extensions/models/_lib/paths.ts`: `absolutePath`, `canonicalPath`, `samePath`, `isWithin`, built on `@std/path/windows` on Windows. Drive-letter, backslash and drive-less paths resolve correctly, and every comparison folds case and separator. The platform rules are injectable (`setPathFlavor`), so the Windows behaviour is tested on macOS/Linux. - `operations.ts`: every worktree path comparison and current-directory base goes through the new module. That covers `ensure_worktree`, `verify_worktree`, `remove_worktree`, `readLayout`, the `requireCleanPrimary` nested filter and the `ensure_checkout` top-level check. - **POSIX behaviour is unchanged.** `absolutePath` keeps the previous join, so `..` is still resolved by the kernel. ### Related fixes, same root cause - `normaliseRemote` on Windows no longer reads `C:/repo` as an scp-style host `c`. `file:///C:/...` decodes to a Windows path, and a malformed escape is kept as-is, as on POSIX. - The `..` guard on worktree `path`/`root` also splits on backslashes (`a\..\b`). ## Testing - `paths_test.ts`: the issue's exact `canonicalPath` cases with cwd `C:\repos\factory`, the reuse root check, separator/case folding, `\\?\` prefix, drive root, symlinked ancestor, UNC, plus POSIX tests that pin the current behaviour. - `git_test.ts`: Windows `normaliseRemote`, rejection of a backslash `..`, `readLayout` + `assertPlacement` over a mocked `C:/` worktree list (reuse passes, the safety checks still refuse), and `remove_worktree` across spellings. - 266 tests pass, and all existing real-git worktree tests are unchanged. Disabling the Windows case/separator folding fails 5 of the new tests. - verify-build and verify-reviews passed on `7280d23`; the attestation is posted. **Caveat:** there is no Windows CI runner, so Windows behaviour is exercised only through the injected Windows rules. We'll ask the reporter to confirm on Windows 11 after release. Manifest bumped to `2026.10.16.1`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Worktree and local-remote paths were handled as POSIX strings. On Windows a
drive-letter path (C:/repos/x) was treated as relative and nested under the
current directory, and once a worktree existed realPathSync returned a
backslash path that never matched the forward-slash root prefix, so reusing
it failed with "outside the worktree root". The primary-checkout, git-dir
and overlap checks never matched git's C:/ listing either.

Paths now go through _lib/paths.ts, built on @std/path/windows on Windows:
drive-letter, backslash and drive-less paths resolve correctly, and every
comparison folds case and separator. POSIX behaviour is unchanged.

Same root cause, same file: normaliseRemote no longer reads C:/repo as an
scp-style host "C", file:///C:/... decodes to a Windows path, and the '..'
guard on worktree path/root also splits on backslashes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(git): inline the @std/path specifier and keep malformed file:// escapes on Windows (swamp-club #3521)
All checks were successful
CI / Review Integrity (pull_request) Successful in 36s
CI / Validate Attestation (pull_request) Successful in 29s
7280d23188
Matches the inline jsr:/npm: specifier style of every other import in the
extension, and keeps a malformed percent escape in a Windows file:// remote
as-is (as POSIX already does) instead of throwing URIError.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
stack72 deleted branch 3521 2026-10-16 22:21:46 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
swamp-club/swamp-extensions!510
No description provided.