mirror of
https://github.com/stablyai/orca.git
synced 2026-11-05 03:27:44 +00:00
perf(worktrees): fetch the base while the host's create picks a name (#26007)
* perf(worktrees): look up a branch's PR only after a name collision on the host's create The host's create (agent.launch, worktree.create, the phone and the CLI) called gh pr list for every create, a 1-3 s network round trip, while the desktop create probes only after a branch collision. A branch with an open PR exists on the remote, so the branch-conflict check already moves past it. * test(worktrees): pin first-name PR lookup skip on the host's create The runtime service specs still expected a PR lookup for a free first name. Update them to the desktop-parity behavior: no lookup without a branch collision, and a free push-target name is kept. Pin the exact suffixed name, and that a later name with a PR is skipped. * perf(worktrees): overlap the host create's base fetch with naming Keep the first-name PR lookup (restores main's naming) and take it off the critical path instead: start the base-ref refresh before naming and await it after, as the desktop create does, so the lookup and the fetch run concurrently. A refresh rejection while naming fails stays handled. * test(worktrees): pin the overlapped origin fetch on the host's create Cover the best-effort fetch origin path: it runs while the first-name PR lookup is pending, and its rejection while naming fails stays handled.
This commit is contained in:
@@ -26,6 +26,54 @@ import {
|
||||
} from '../worktree-name-retirement'
|
||||
import type { WorktreeCreateTimingRecorder } from '../worktree-create-timing'
|
||||
|
||||
export type RuntimeLocalBaseRefRefresh = {
|
||||
/** Awaits the deferred refresh started before naming, if any. */
|
||||
finish: () => Promise<void>
|
||||
}
|
||||
|
||||
// Why: the deferred refresh can change neither the base nor the name, so start it before naming
|
||||
// and await it before the add, as the desktop create does; naming's PR lookup overlaps it.
|
||||
export function startRuntimeLocalBaseRefRefresh(args: {
|
||||
repoPath: string
|
||||
base: RuntimeLocalWorktreeCreateBase
|
||||
localWorktreeGitOptions: LocalGitExecOptions
|
||||
refreshRemoteTrackingBase: (
|
||||
repoPath: string,
|
||||
base: RemoteTrackingBase,
|
||||
options?: LocalGitExecOptions
|
||||
) => Promise<RemoteFetchResult>
|
||||
fetchRemote: (repoPath: string, remote: string, options?: LocalGitExecOptions) => Promise<void>
|
||||
timing: WorktreeCreateTimingRecorder
|
||||
}): RuntimeLocalBaseRefRefresh {
|
||||
const { remoteTrackingBase, deferredRefresh } = args.base
|
||||
if (remoteTrackingBase && deferredRefresh === 'tracking_ref') {
|
||||
const refresh = args.refreshRemoteTrackingBase(
|
||||
args.repoPath,
|
||||
remoteTrackingBase,
|
||||
args.localWorktreeGitOptions
|
||||
)
|
||||
// Why: naming can throw before finish() awaits the refresh.
|
||||
void refresh.catch(() => undefined)
|
||||
return {
|
||||
finish: async () => {
|
||||
await args.timing.time('refresh_base_ref', () => refresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deferredRefresh === 'origin') {
|
||||
const originFetch = args.fetchRemote(args.repoPath, 'origin', args.localWorktreeGitOptions)
|
||||
void originFetch.catch(() => undefined)
|
||||
return {
|
||||
finish: async () => {
|
||||
try {
|
||||
await args.timing.time('refresh_base_ref', () => originFetch)
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { finish: async () => {} }
|
||||
}
|
||||
|
||||
export async function createRuntimeLocalGitWorktree(args: {
|
||||
request: RuntimeManagedWorktreeCreateArgs
|
||||
repo: Repo
|
||||
@@ -43,12 +91,7 @@ export async function createRuntimeLocalGitWorktree(args: {
|
||||
effectiveSanitizedName?: string
|
||||
checkoutExistingBranch: boolean
|
||||
localWorktreeGitOptions: LocalGitExecOptions
|
||||
refreshRemoteTrackingBase: (
|
||||
repoPath: string,
|
||||
base: RemoteTrackingBase,
|
||||
options?: LocalGitExecOptions
|
||||
) => Promise<RemoteFetchResult>
|
||||
fetchRemote: (repoPath: string, remote: string, options?: LocalGitExecOptions) => Promise<void>
|
||||
baseRefRefresh: RuntimeLocalBaseRefRefresh
|
||||
rearm: PreparationRearmHolder
|
||||
timing: WorktreeCreateTimingRecorder
|
||||
}): Promise<{
|
||||
@@ -57,22 +100,8 @@ export async function createRuntimeLocalGitWorktree(args: {
|
||||
created: GitWorktreeInfo
|
||||
addResult: AddWorktreeResult
|
||||
}> {
|
||||
const { baseBranch, remoteTrackingBase, deferredRefresh } = args.base
|
||||
if (remoteTrackingBase && deferredRefresh === 'tracking_ref') {
|
||||
await args.timing.time('refresh_base_ref', () =>
|
||||
args.refreshRemoteTrackingBase(
|
||||
args.repo.path,
|
||||
remoteTrackingBase,
|
||||
args.localWorktreeGitOptions
|
||||
)
|
||||
)
|
||||
} else if (deferredRefresh === 'origin') {
|
||||
try {
|
||||
await args.timing.time('refresh_base_ref', () =>
|
||||
args.fetchRemote(args.repo.path, 'origin', args.localWorktreeGitOptions)
|
||||
)
|
||||
} catch {}
|
||||
}
|
||||
const { baseBranch, remoteTrackingBase } = args.base
|
||||
await args.baseRefRefresh.finish()
|
||||
const sparseDirectories = args.request.sparseCheckout
|
||||
? normalizeSparseDirectories(args.request.sparseCheckout.directories)
|
||||
: []
|
||||
|
||||
Reference in New Issue
Block a user