Files
orca/src/relay/git-handler-branch-compare.test.ts
T
NeilandOrca a49d68f8c2 perf(git): overlap getBranchCompare's head-of-chain reads (#10895)
* perf(git): overlap getBranchCompare's head-of-chain reads

Four git spawns ran strictly in series before any compare work began:
branch --show-current, the base-ref probe, rev-parse HEAD, and rev-parse <base>.

Three are independent -- compareRef is display-only metadata and HEAD's oid does
not depend on the base ref -- so they now run concurrently. The fourth was
redundant outright: the probe already runs `rev-parse --verify --quiet
<ref>^{commit}` and discarded the oid it printed, which was then re-resolved by a
second spawn. resolveWorktreeBaseCommitOid returns that oid so it can be reused;
hasWorktreeBaseCommitRef now delegates to it, leaving its other 4 callers
untouched.

3.6-3.7x on a short remote base label (192ms -> 52ms), 1.44x on an
already-qualified refs/... base, which skips the probe by design.

Reuse is keyed by ref: resolveWorktreeAddBaseRef returns at its first successful
candidate, so only that ref's oid is ever read back. Peeling is safe because only
refs/heads and refs/remotes candidates reach the probe, where ^{commit} is a
no-op.

No new git features: this removes a spawn rather than adopting an option.

Co-authored-by: Orca <help@stably.ai>

* fix(git): preserve compare semantics across providers

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-27 17:17:03 -07:00

59 lines
2.1 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import { branchCompare, type GitExec } from './git-handler-ops'
function deferred<T>(): { promise: Promise<T>; resolve: (value: T) => void } {
let resolve!: (value: T) => void
const promise = new Promise<T>((innerResolve) => {
resolve = innerResolve
})
return { promise, resolve }
}
describe('relay branchCompare', () => {
it('launches independent Git reads before waiting for any result', async () => {
const branch = deferred<{ stdout: string; stderr: string }>()
const head = deferred<{ stdout: string; stderr: string }>()
const base = deferred<{ stdout: string; stderr: string }>()
const changes = deferred<Record<string, unknown>[]>()
const git = vi.fn<GitExec>((args) => {
if (args[0] === 'branch') {
return branch.promise
}
if (args[0] === 'rev-parse' && args.includes('HEAD')) {
return head.promise
}
if (args[0] === 'rev-parse') {
return base.promise
}
if (args[0] === 'merge-base') {
return Promise.resolve({ stdout: 'merge-base\n', stderr: '' })
}
if (args[0] === 'rev-list') {
return Promise.resolve({ stdout: '1\n', stderr: '' })
}
throw new Error(`Unexpected git command: ${args.join(' ')}`)
})
const loadBranchChanges = vi.fn(() => changes.promise)
const pending = branchCompare(git, '/repo', 'origin/main', loadBranchChanges)
await Promise.resolve()
expect(git.mock.calls.map(([args]) => args.join(' '))).toEqual([
'branch --show-current',
'rev-parse --verify HEAD',
'rev-parse --verify origin/main'
])
branch.resolve({ stdout: 'feature\n', stderr: '' })
head.resolve({ stdout: 'head\n', stderr: '' })
base.resolve({ stdout: 'base\n', stderr: '' })
await vi.waitFor(() => expect(loadBranchChanges).toHaveBeenCalledOnce())
expect(git.mock.calls.some(([args]) => args[0] === 'rev-list')).toBe(true)
changes.resolve([{ path: 'file.ts' }])
await expect(pending).resolves.toMatchObject({
summary: { compareRef: 'feature', changedFiles: 1, commitsAhead: 1, status: 'ready' }
})
})
})