mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 08:03:28 +00:00
* fix(worktrees): remove repeated scans and keep prepared checkouts fresh * fix(worktrees): reclaim unlocked fallback preparations safely * refactor(worktrees): simplify creation ownership and idle maintenance * fix(git): keep ref maintenance armed after an index-only pass An idle attempt that found the pack index due but refs still cooling down returned without rescheduling, so loose refs from the arming fetch waited for the next write instead of the ref cooldown.
170 lines
5.7 KiB
TypeScript
170 lines
5.7 KiB
TypeScript
import { isFolderRepo } from '../shared/repo-kind'
|
|
import type { Repo } from '../shared/repo-types'
|
|
import { isFullGitObjectId } from './git/commit-object-ref'
|
|
import { hasLocalWorktreeBaseRef } from './git/worktree-base-ref-probe'
|
|
import { getBaseRefDefault } from './git/repo'
|
|
import { getSshGitProvider } from './providers/ssh-git-dispatch'
|
|
import { prefetchRemoteWorktreeCreateBase } from './ipc/worktree-remote'
|
|
import { resolveWorktreeCreateBase } from './worktree-create-base'
|
|
|
|
type WorktreeCreateBaseGitOptions = {
|
|
wslDistro?: string
|
|
}
|
|
|
|
type RemoteTrackingBaseForPrefetch = {
|
|
remote: string
|
|
branch: string
|
|
ref: string
|
|
base: string
|
|
}
|
|
|
|
type WorktreeCreateBasePrefetchRuntime = {
|
|
resolveRemoteTrackingBase: (
|
|
repoPath: string,
|
|
baseBranch: string,
|
|
options?: WorktreeCreateBaseGitOptions
|
|
) => Promise<RemoteTrackingBaseForPrefetch | null>
|
|
hasRemoteTrackingRef: (
|
|
repoPath: string,
|
|
base: RemoteTrackingBaseForPrefetch,
|
|
options?: WorktreeCreateBaseGitOptions
|
|
) => Promise<boolean>
|
|
getOrStartRemoteTrackingBaseRefresh: (
|
|
repoPath: string,
|
|
base: RemoteTrackingBaseForPrefetch,
|
|
options?: WorktreeCreateBaseGitOptions
|
|
) => Promise<{ ok: boolean }>
|
|
fetchRemoteWithCache: (
|
|
repoPath: string,
|
|
remote: string,
|
|
options?: WorktreeCreateBaseGitOptions
|
|
) => Promise<void>
|
|
}
|
|
|
|
async function prefetchLocalWorktreeCreateBase(
|
|
repo: Repo,
|
|
baseBranch: string | undefined,
|
|
runtime: WorktreeCreateBasePrefetchRuntime,
|
|
options: WorktreeCreateBaseGitOptions,
|
|
prepareLocalCheckout: (base: string, beforeMaterialization?: Promise<void>) => void
|
|
): Promise<string | undefined> {
|
|
// Keep host-routed calls at their original arity so they stay on the runtime's default options.
|
|
const optionArgs: [] | [WorktreeCreateBaseGitOptions] = options.wslDistro ? [options] : []
|
|
const resolvedBaseBranch = await resolveWorktreeCreateBase({
|
|
requestedBaseBranch: baseBranch,
|
|
repoWorktreeBaseRef: repo.worktreeBaseRef,
|
|
resolveDefaultBaseRef: () => getBaseRefDefault(repo.path, ...optionArgs),
|
|
isBaseUsable: async (baseBranchCandidate) => {
|
|
const remoteTrackingBase = await runtime.resolveRemoteTrackingBase(
|
|
repo.path,
|
|
baseBranchCandidate,
|
|
...optionArgs
|
|
)
|
|
if (remoteTrackingBase) {
|
|
if (await runtime.hasRemoteTrackingRef(repo.path, remoteTrackingBase, ...optionArgs)) {
|
|
return true
|
|
}
|
|
return hasLocalWorktreeBaseRef(repo.path, baseBranchCandidate, options)
|
|
}
|
|
return hasLocalWorktreeBaseRef(repo.path, baseBranchCandidate, options)
|
|
}
|
|
})
|
|
if (!resolvedBaseBranch) {
|
|
return undefined
|
|
}
|
|
if (
|
|
isFullGitObjectId(resolvedBaseBranch) &&
|
|
(await hasLocalWorktreeBaseRef(repo.path, resolvedBaseBranch, options))
|
|
) {
|
|
return resolvedBaseBranch
|
|
}
|
|
const remoteTrackingBase = await runtime.resolveRemoteTrackingBase(
|
|
repo.path,
|
|
resolvedBaseBranch,
|
|
...optionArgs
|
|
)
|
|
if (remoteTrackingBase) {
|
|
const hasTrackingRef = await runtime.hasRemoteTrackingRef(
|
|
repo.path,
|
|
remoteTrackingBase,
|
|
...optionArgs
|
|
)
|
|
if (
|
|
hasTrackingRef ||
|
|
!(await hasLocalWorktreeBaseRef(repo.path, resolvedBaseBranch, options))
|
|
) {
|
|
const refresh = runtime.getOrStartRemoteTrackingBaseRefresh(
|
|
repo.path,
|
|
remoteTrackingBase,
|
|
...optionArgs
|
|
)
|
|
if (hasTrackingRef) {
|
|
// Register during fetch, then materialize the settled base once; offline keeps its local tip.
|
|
const beforeMaterialization = refresh.then(
|
|
() => {},
|
|
() => {}
|
|
)
|
|
prepareLocalCheckout(resolvedBaseBranch, beforeMaterialization)
|
|
}
|
|
await refresh
|
|
return resolvedBaseBranch
|
|
}
|
|
}
|
|
if (await hasLocalWorktreeBaseRef(repo.path, resolvedBaseBranch, options)) {
|
|
// Why: hosted-review start points and local branch bases are already local; a broad remote fetch cannot make them fresher.
|
|
return resolvedBaseBranch
|
|
}
|
|
|
|
// Why: same best-effort fallback create takes, on create's own fetch key, so a
|
|
// create that lands here reuses this fetch instead of repeating it. A create
|
|
// that instead resolves an exact remote base still queues behind it.
|
|
await runtime.fetchRemoteWithCache(repo.path, 'origin', ...optionArgs)
|
|
return resolvedBaseBranch
|
|
}
|
|
|
|
export async function prefetchWorktreeCreateBase(args: {
|
|
repo: Repo
|
|
baseBranch?: string
|
|
runtime: WorktreeCreateBasePrefetchRuntime
|
|
/** Routing for the project's Git host; required so a caller cannot silently
|
|
* warm up the wrong ref store — pass `{}` for host Git. */
|
|
gitOptions: WorktreeCreateBaseGitOptions
|
|
prepareCheckout?: (base: string, beforeMaterialization?: Promise<void>) => Promise<void>
|
|
}): Promise<string | undefined> {
|
|
if (isFolderRepo(args.repo)) {
|
|
return undefined
|
|
}
|
|
if (args.repo.connectionId) {
|
|
const provider = getSshGitProvider(args.repo.connectionId)
|
|
if (!provider) {
|
|
return undefined
|
|
}
|
|
await prefetchRemoteWorktreeCreateBase(provider, args.repo, { baseBranch: args.baseBranch })
|
|
return undefined
|
|
}
|
|
const prepareCheckout = args.prepareCheckout
|
|
let preparation: Promise<void> | undefined
|
|
const prepare = (base: string, beforeMaterialization?: Promise<void>): void => {
|
|
if (!preparation && prepareCheckout) {
|
|
preparation = Promise.resolve().then(() => prepareCheckout(base, beforeMaterialization))
|
|
}
|
|
void preparation?.catch(() => {})
|
|
}
|
|
try {
|
|
const base = await prefetchLocalWorktreeCreateBase(
|
|
args.repo,
|
|
args.baseBranch,
|
|
args.runtime,
|
|
args.gitOptions,
|
|
prepare
|
|
)
|
|
if (base) {
|
|
prepare(base)
|
|
}
|
|
return base
|
|
} finally {
|
|
// Settle speculative work even if refresh fails; Create owns error reporting.
|
|
await preparation?.catch(() => {})
|
|
}
|
|
}
|