Files
orca/src/main/project-runtime-git-options.ts
T
Neil abc099e4c7 fix(worktree): run the create-base warm-up on the routed git host (#17794)
The speculative warm-up that runs while the create composer is open resolved
refs and fetched with host Git even when the project's runtime is a WSL distro,
while both the checkout preparation it feeds (`prepareWorktreeCreateForRepo`,
which already resolves `{ wslDistro }` itself) and the real create path run
inside the distro.

The concrete cost was a discarded fetch: `getCanonicalFetchKey` namespaces the
runtime's remote-fetch cache `wsl:<distro>` vs `local`, so the warm-up's fetch
landed in a namespace create never looks at, and create fetched again. On a
Windows host with no usable host-side Git the probes also failed outright, so
that cohort got no warm-up at all.

Thread the project's worktree Git options through the prefetch (resolved by a
non-throwing helper, because an optimistic warm-up must not surface a
repair-required runtime as a failure) so every probe and fetch runs where create
runs. `gitOptions` is a required argument, so a caller cannot drop the routing
silently. Host-routed calls keep their original arity, so macOS, Linux,
native-Windows-host projects, SSH repos and folder workspaces are unchanged.

Narrower than it looks: for a repo under \\wsl.localhost\<distro>\... the probes
were already routed by cwd, and for a repo on a Windows drive letter host Git
and WSL Git read the same on-disk repository, so the answers were already
correct there. What those cohorts gain is a fetch create can reuse; what they
pay is that the probes now run inside the distro (over /mnt/c for drive-letter
repos, which also newly arms the linked-worktree routing probe) and the
speculative fetch now shares create's per-remote fetch queue, as it always has
on native platforms.

Also collapse the three byte-equivalent copies of `hasLocalWorktreeBaseRef`
(create, prefetch, remote-repo create) into one in
git/worktree-base-ref-probe.ts, drop the host-only `hasLocalCommitObject` that
caused the routing bug, and add the first routing assertions on the create-path
consumers of the now-shared probe.
2026-08-31 20:32:59 -07:00

111 lines
3.6 KiB
TypeScript

import type { Store } from './persistence'
import type { Repo } from '../shared/repo-types'
import { isFolderRepo } from '../shared/repo-kind'
import {
resolveLocalProjectRuntimeForRepo,
type ProjectRuntimeResolutionStore
} from './local-project-runtime-resolution'
import type { ProjectExecutionRuntimeResolution } from '../shared/project-execution-runtime'
export {
resolveLocalProjectRuntimeForRepo,
resolveLocalProjectRuntimesForRepos
} from './local-project-runtime-resolution'
export type LocalProjectGitExecOptions = {
cwd: string
wslDistro?: string
}
export type LocalProjectWorktreeGitOptions = {
wslDistro?: string
}
export function getLocalProjectGitExecOptions(
store: Store,
repo: Repo
): LocalProjectGitExecOptions {
// Why: local git must run in the same resolved project runtime as agents,
// terminals, and preflight; repair states must not silently fall back to host git.
return getLocalProjectGitExecOptionsForRuntime(
repo,
resolveLocalProjectRuntimeForRepo(store, repo)
)
}
function getLocalProjectGitExecOptionsForRuntime(
repo: Repo,
projectRuntime: ProjectExecutionRuntimeResolution | undefined
): LocalProjectGitExecOptions {
if (!projectRuntime) {
return { cwd: repo.path }
}
if (projectRuntime.status === 'repair-required') {
throw new Error(
`Project runtime requires repair before git execution: ${projectRuntime.repair.reason}`
)
}
if (projectRuntime.runtime.kind === 'wsl') {
return { cwd: repo.path, wslDistro: projectRuntime.runtime.distro }
}
return { cwd: repo.path }
}
export function getLocalProjectWorktreeGitOptions(
store: Store,
repo: Repo
): LocalProjectWorktreeGitOptions {
const { wslDistro } = getLocalProjectGitExecOptions(store, repo)
return wslDistro ? { wslDistro } : {}
}
/**
* Git routing for the speculative worktree-create warm-up.
*
* Deliberately non-throwing where `getLocalProjectWorktreeGitOptions` throws: an
* optimistic prefetch must not report a repair-required runtime as a failure, so
* an unresolved runtime falls back to the host Git the warm-up used before
* routing existed.
*/
export function getWorktreeCreatePrefetchGitOptions(
store: Store,
repo: Repo
): LocalProjectWorktreeGitOptions {
if (isFolderRepo(repo)) {
return {}
}
const projectRuntime = resolveLocalProjectRuntimeForRepo(store, repo)
if (!projectRuntime || projectRuntime.status !== 'resolved') {
return {}
}
return getLocalProjectWorktreeGitOptionsForRuntime(repo, projectRuntime)
}
export function getLocalProjectWorktreeGitOptionsForRuntime(
repo: Repo,
projectRuntime: ProjectExecutionRuntimeResolution | undefined
): LocalProjectWorktreeGitOptions {
// Why: callers that already batch-resolved project runtimes must not rescan
// every project once per repo on a polling path.
const { wslDistro } = getLocalProjectGitExecOptionsForRuntime(repo, projectRuntime)
return wslDistro ? { wslDistro } : {}
}
/**
* Distro whose filesystem this repo's worktrees belong on, or undefined.
*
* Deliberately non-throwing where `getLocalProjectGitExecOptions` throws: a
* runtime that needs repair must not block creating a worktree, it just falls
* back to the Windows-side placement that has always been used.
*/
export function getWorktreeMirrorDistro(
store: ProjectRuntimeResolutionStore,
repo: Repo
): string | undefined {
const projectRuntime = resolveLocalProjectRuntimeForRepo(store, repo)
if (!projectRuntime || projectRuntime.status !== 'resolved') {
return undefined
}
return projectRuntime.runtime.kind === 'wsl' ? projectRuntime.runtime.distro : undefined
}