Files
orca/src/shared/git-metadata-path.ts
T
Neil a9babde9a3 refactor(git): accept a caller-named WSL distro on the metadata path resolver (#17804)
Two small changes to the Git metadata read path. Neither has a user-visible
effect on any platform except for a malformed `.git` gitfile, described below.

1. resolveGitMetadataPath's third parameter becomes an options object
   `{ platform?, wslDistro? }`. A caller that knows which distro wrote a pointer
   can now say so, where previously only a WSL UNC base path could. The distro
   encoded in the base path still outranks the caller's, and translation only
   happens when the reading host is win32, so a caller-named distro cannot make
   a POSIX host fabricate a Windows path. The UNC-base branch is exempt from
   that gate because that spelling only exists on Windows. Main's other
   contracts are verbatim: never null for a non-empty pointer, and a drvfs
   pointer keeps its drive spelling even when a distro is named. Both production
   call sites (repo-git-marker-scan.ts) pass no options, so they are unchanged.

2. The `.git` gitfile marker parse moves into one shared function,
   parseGitdirMarkerPayload: `gitdir:` at the start of the file, payload
   trimmed, empty payload rejected — git's own read_gitfile_gently rule.
   resolve-git-dir.ts and repo-git-marker-scan.ts both call it; the latter had a
   near-identical private copy and is behaviorally identical after the swap
   (verified across twelve marker spellings; the only divergence, a
   whitespace-only payload, already resolved to null one call further down).
   Main's `/^gitdir:\s*(.+)\s*$/m` in resolve-git-dir captured trailing padding
   into the path and honored a `gitdir:` line anywhere in the file.

Per-platform delta: none on macOS, Linux, native Windows, WSL, SSH, relay, or
folder workspaces. The wslDistro option is inert; this change adds no caller.
For a malformed `.git` gitfile, padding is now stripped (strict improvement), a
whitespace-only payload falls back to `<worktree>/.git`, and a `gitdir:` line
that is not the first line is no longer honored — a narrowing, since main could
return a working gitdir there. All four resolveGitDir consumers already degrade
through a catch, so that case reports no sparse state / conflict operation /
diff stamp rather than failing.

Six other hand-rolled `gitdir:` parsers remain, including the relay's SSH copy;
converging them is its own change.
2026-08-31 22:37:09 -07:00

62 lines
2.2 KiB
TypeScript

import { posix, win32 } from 'node:path'
import { parseWslUncPath, toWindowsWslDrivePath, toWindowsWslPath } from './wsl-paths'
export type GitMetadataPathOptions = {
/** Host that reads the pointer back. Defaults to the current process platform. */
platform?: NodeJS.Platform
/** Distro that wrote the pointer, for callers whose base path does not encode one. Windows-only. */
wslDistro?: string
}
/**
* Resolve a Git metadata pointer (a `.git` gitfile payload or a `commondir`) in the path namespace
* of the host that reads it.
*
* Why: git running inside WSL writes these pointers in the guest namespace, but Node reads them
* back through Win32, where a drvfs pointer like `/mnt/c/repo/.git` silently means
* `C:\mnt\c\repo\.git`. Returns null only for an empty pointer.
*/
export function resolveGitMetadataPath(
basePath: string,
rawPath: string,
options: GitMetadataPathOptions = {}
): string | null {
const platform = options.platform ?? process.platform
const value = rawPath.trim()
if (!value) {
return null
}
if (value.startsWith('/')) {
const translated = translateGuestPointer(value, basePath, platform, options.wslDistro)
if (translated) {
return translated
}
}
const host = platform === 'win32' ? win32 : posix
return host.isAbsolute(value) ? value : host.resolve(basePath, value)
}
/**
* The Win32 spelling of a POSIX-rooted pointer, or null to leave it alone. A WSL UNC base names the
* distro that wrote the pointer and outranks the caller's guess; failing both, only a drvfs mount
* has a spelling we can derive.
*
* Only a Windows host is translated at all, so a caller-named distro cannot make a POSIX host
* fabricate a Win32 path. A WSL UNC base is exempt because that spelling only exists on Windows.
*/
function translateGuestPointer(
value: string,
basePath: string,
platform: NodeJS.Platform,
wslDistro: string | undefined
): string | null {
const baseDistro = parseWslUncPath(basePath)?.distro
if (baseDistro) {
return toWindowsWslPath(value, baseDistro)
}
if (platform !== 'win32') {
return null
}
return wslDistro ? toWindowsWslPath(value, wslDistro) : toWindowsWslDrivePath(value)
}