mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 08:03:33 +00:00
* 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>
59 lines
2.1 KiB
TypeScript
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' }
|
|
})
|
|
})
|
|
})
|