fix(git): preserve WSL fast reads after expected failures

This commit is contained in:
OrcaWin
2026-08-08 07:42:12 -07:00
parent b6b59dbc26
commit ac37713a54
2 changed files with 59 additions and 9 deletions
@@ -270,6 +270,46 @@ describe('WSL direct Git reads', () => {
})
})
it('keeps the fast path when direct and login Git both report an expected failure', async () => {
await withPlatform('win32', async () => {
seedWslGitReadEnvironmentForTests(DISTRO, LOGIN_ENVIRONMENT)
execFileMock
.mockImplementationOnce((_command, _args, _options, callback) => {
const child = createMockChild()
queueMicrotask(() =>
callback?.(Object.assign(new Error('exit 1'), { code: 1 }), '', 'missing ref')
)
return child
})
.mockImplementationOnce((_command, _args, _options, callback) => {
const child = createMockChild()
queueMicrotask(() =>
callback?.(Object.assign(new Error('exit 1'), { code: 1 }), '', 'missing ref')
)
return child
})
.mockImplementationOnce((_command, _args, _options, callback) => {
const child = createMockChild()
queueMicrotask(() => callback?.(null, 'ok', ''))
return child
})
const options = {
cwd: String.raw`C:\repo`,
preferWslDirectGit: true as const,
wslDistro: DISTRO
}
await expect(gitExecFileAsync(['rev-parse', '--verify', 'missing'], options)).rejects.toThrow(
'exit 1'
)
await gitExecFileAsync(['status', '--short'], options)
expect(execFileMock.mock.calls[0]?.[1]).toContain('--exec')
expect(execFileMock.mock.calls[1]?.[1]?.slice(3, 5)).toEqual(['sh', '-lc'])
expect(execFileMock.mock.calls[2]?.[1]).toContain('--exec')
})
})
it('streams opted-in reads directly', async () => {
await withPlatform('win32', async () => {
seedWslGitReadEnvironmentForTests(DISTRO, LOGIN_ENVIRONMENT)
+19 -9
View File
@@ -387,13 +387,19 @@ function directWslGitExitCode(error: unknown, resolved: ResolvedCommand): number
return typeof code === 'number' ? code : null
}
function disableOrInvalidateDirectWslGit(error: unknown, resolved: ResolvedCommand): void {
if (!resolved.wsl) {
return
}
if (isDirectWslGitNotFound(error, resolved)) {
function invalidateMissingDirectWslGit(error: unknown, resolved: ResolvedCommand): boolean {
const isMissing = isDirectWslGitNotFound(error, resolved)
if (isMissing && resolved.wsl) {
invalidateWslGitReadEnvironment(resolved.wsl.distro)
} else {
}
return isMissing
}
function disableDirectWslGitAfterSuccessfulFallback(
wasMissing: boolean,
resolved: ResolvedCommand
): void {
if (!wasMissing && resolved.wsl) {
disableWslGitReadEnvironment(resolved.wsl.distro)
}
}
@@ -979,8 +985,10 @@ export async function gitExecFileAsync(
result = await capture(resolved)
} catch (error) {
if (directWslGitExitCode(error, resolved) !== null && !options.signal?.aborted) {
disableOrInvalidateDirectWslGit(error, resolved)
const wasMissing = invalidateMissingDirectWslGit(error, resolved)
result = await capture(resolveGitCommand(args, options, true))
// Why: matching failures can be normal Git control flow; only a successful login retry proves the direct environment was insufficient.
disableDirectWslGitAfterSuccessfulFallback(wasMissing, resolved)
const { stdout, stderr } = result
return { stdout: stdout as string, stderr: stderr as string }
}
@@ -1232,9 +1240,11 @@ export async function gitStreamStdout(
directWslGitExitCode(error, resolved) !== null &&
!options.signal?.aborted
) {
disableOrInvalidateDirectWslGit(error, resolved)
const wasMissing = invalidateMissingDirectWslGit(error, resolved)
resolved = resolveGitCommandWithoutProbe(args, gitOptions)
return stream(resolved)
const result = await stream(resolved)
disableDirectWslGitAfterSuccessfulFallback(wasMissing, resolved)
return result
}
throw error
}