mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 08:03:12 +00:00
perf: preserve user Git checkout worker settings
This commit is contained in:
@@ -53,17 +53,6 @@ in one record and pick at parse time.
|
||||
| --------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `%(decorate:…)` | Git 2.43 separates commit decorations with `\x1f`, so ref names containing commas survive | The same record also carries `%D` (Git 2.10); an unexpanded `%(decorate` placeholder selects it, at the cost of comma-splitting |
|
||||
|
||||
### Parallel checkout configuration
|
||||
|
||||
Native macOS worktree creation and prepared-checkout materialization pass the
|
||||
command-local setting `-c checkout.workers=4`. Parallel checkout arrived in Git
|
||||
2.32; Git 2.25–2.31 accepts and ignores this unknown configuration key, preserving
|
||||
serial checkout without a rejected command or retry. No capability-cache entry is
|
||||
needed for this setting. The real-binary contract checks the worker boundary using
|
||||
Trace2 and verifies checked-out content and clean status. Windows, WSL, Linux, and
|
||||
SSH keep their existing checkout settings pending host measurements. The setting
|
||||
is never persisted to repository or user configuration.
|
||||
|
||||
## Why Not `simple-git`
|
||||
|
||||
`simple-git` is a process wrapper around the installed Git binary. Its custom
|
||||
|
||||
@@ -167,7 +167,7 @@ branch refs/heads/main
|
||||
const calls = getGitCalls()
|
||||
expect(calls).toEqual(
|
||||
expect.arrayContaining([
|
||||
'git -c checkout.workers=4 worktree add --no-checkout --no-track -b feature/test /repo-feature',
|
||||
'git worktree add --no-checkout --no-track -b feature/test /repo-feature',
|
||||
'git config --get push.autoSetupRemote',
|
||||
'git config --local push.autoSetupRemote true',
|
||||
'git sparse-checkout init --cone',
|
||||
|
||||
@@ -68,8 +68,6 @@ describe('addWorktree', () => {
|
||||
[['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -104,7 +102,7 @@ describe('addWorktree', () => {
|
||||
|
||||
expect(gitExecFileAsyncMock.mock.calls).toEqual([
|
||||
[
|
||||
['-c', 'checkout.workers=4', 'worktree', 'add', '/repo-feature', 'feature/test'],
|
||||
['worktree', 'add', '/repo-feature', 'feature/test'],
|
||||
{ cwd: '/repo', timeout: WORKTREE_ADD_TIMEOUT_MS }
|
||||
]
|
||||
])
|
||||
@@ -184,13 +182,7 @@ describe('addWorktree', () => {
|
||||
})
|
||||
|
||||
expect(gitExecFileAsyncMock).toHaveBeenCalledWith(
|
||||
[
|
||||
...(platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'/repo-feature',
|
||||
'feature/test'
|
||||
],
|
||||
['worktree', 'add', '/repo-feature', 'feature/test'],
|
||||
{ cwd: '/repo', timeout: WORKTREE_ADD_TIMEOUT_MS }
|
||||
)
|
||||
}
|
||||
@@ -235,16 +227,7 @@ describe('addWorktree', () => {
|
||||
|
||||
expect(gitExecFileAsyncMock.mock.calls).toEqual([
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
'-b',
|
||||
'feature/no-base',
|
||||
'/repo-feature'
|
||||
],
|
||||
['worktree', 'add', '--no-track', '-b', 'feature/no-base', '/repo-feature'],
|
||||
{ cwd: '/repo', timeout: WORKTREE_ADD_TIMEOUT_MS }
|
||||
],
|
||||
[['config', '--get', 'push.autoSetupRemote'], { cwd: '/repo-feature' }]
|
||||
@@ -319,8 +302,6 @@ describe('addWorktree', () => {
|
||||
[['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -359,8 +340,6 @@ describe('addWorktree', () => {
|
||||
[['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -400,8 +379,6 @@ describe('addWorktree', () => {
|
||||
[['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -442,8 +419,6 @@ describe('addWorktree', () => {
|
||||
[['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -475,8 +450,6 @@ describe('addWorktree', () => {
|
||||
])
|
||||
expect(gitExecFileAsyncMock.mock.calls[1]).toEqual([
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -503,8 +476,6 @@ describe('addWorktree', () => {
|
||||
['rev-parse', '--verify', '--quiet', 'refs/remotes/release/main^{commit}'],
|
||||
['rev-parse', '--verify', '--quiet', 'refs/heads/release/main^{commit}'],
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -546,8 +517,6 @@ describe('addWorktree', () => {
|
||||
['rev-parse', '--verify', '--quiet', 'refs/remotes/release/main^{commit}'],
|
||||
['rev-parse', '--verify', '--quiet', 'refs/heads/release/main^{commit}'],
|
||||
[
|
||||
'-c',
|
||||
'checkout.workers=4',
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
|
||||
@@ -82,7 +82,6 @@ describe('addWorktree', () => {
|
||||
[['reset', '--hard', 'remote-main'], { cwd: '/repo' }],
|
||||
[
|
||||
[
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -320,7 +319,6 @@ describe('addWorktree', () => {
|
||||
'refs/remotes/origin/main^{commit}'
|
||||
])
|
||||
expect(gitExecFileAsyncMock.mock.calls[7]?.[0]).toEqual([
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -380,7 +378,6 @@ describe('addWorktree', () => {
|
||||
],
|
||||
[
|
||||
[
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -437,7 +434,6 @@ describe('addWorktree', () => {
|
||||
|
||||
expect(result.localBaseRefRefresh).toBeUndefined()
|
||||
expect(gitExecFileAsyncMock.mock.calls.map((call) => call[0])).toContainEqual([
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
@@ -559,7 +555,6 @@ describe('addWorktree', () => {
|
||||
],
|
||||
[
|
||||
[
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
|
||||
@@ -95,7 +95,6 @@ describe('addWorktree', () => {
|
||||
['rev-parse', '--verify', '--quiet', 'refs/remotes/origin/main^{commit}'],
|
||||
['rev-list', '--left-right', '--count', 'refs/heads/main...refs/remotes/origin/main'],
|
||||
[
|
||||
...(process.platform === 'darwin' ? ['-c', 'checkout.workers=4'] : []),
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
|
||||
@@ -20,7 +20,6 @@ import type {
|
||||
} from './worktree-operation-options'
|
||||
import { gitExecOptions, resolveWorktreeAddTimeoutMs } from './worktree-operation-options'
|
||||
import { bumpWorktreeScanGeneration } from './worktree-scan-cache'
|
||||
import { worktreeCheckoutGitArgs } from '../../shared/worktree-checkout-config'
|
||||
|
||||
export type WorktreeAddBaseContext = AddWorktreeResult & {
|
||||
effectiveBase: string
|
||||
@@ -188,12 +187,7 @@ async function performAddWorktree(
|
||||
let localBaseRefRefresh: LocalBaseRefRefreshResult | undefined
|
||||
let localBaseRefUpdateSuggestion: LocalBaseRefUpdateSuggestion | undefined
|
||||
// Why: enable long paths for this Windows checkout without changing user Git config.
|
||||
const args = [
|
||||
...windowsLongPathGitArgs(repoPath),
|
||||
...worktreeCheckoutGitArgs(options),
|
||||
'worktree',
|
||||
'add'
|
||||
]
|
||||
const args = [...windowsLongPathGitArgs(repoPath), 'worktree', 'add']
|
||||
let effectiveBase: string | undefined
|
||||
if (noCheckout) {
|
||||
args.push('--no-checkout')
|
||||
|
||||
@@ -14,7 +14,6 @@ import { withRepoRefMaintenancePaused } from './local-repo-ref-maintenance'
|
||||
import { gitExecFileAsync } from './runner'
|
||||
import { runWithGitReadCacheInvalidation } from './status'
|
||||
import { invalidateWslLinkedWorktreeGitRouting } from './wsl-linked-worktree-git-routing'
|
||||
import { worktreeCheckoutGitArgs } from '../../shared/worktree-checkout-config'
|
||||
|
||||
function gitExecOptions(
|
||||
cwd: string,
|
||||
@@ -93,13 +92,7 @@ export async function prepareWorktreeCreateCheckout(
|
||||
invalidateWslLinkedWorktreeGitRouting(worktreePath)
|
||||
// Why: reset materializes files without running user post-checkout hooks before submit.
|
||||
await gitExecFileAsync(
|
||||
[
|
||||
...windowsLongPathGitArgs(worktreePath),
|
||||
...worktreeCheckoutGitArgs(options),
|
||||
'reset',
|
||||
'--hard',
|
||||
effectiveBase
|
||||
],
|
||||
[...windowsLongPathGitArgs(worktreePath), 'reset', '--hard', effectiveBase],
|
||||
{ ...gitExecOptions(worktreePath, options), timeout: resolveWorktreeAddTimeoutMs() }
|
||||
)
|
||||
await gitExecFileAsync(
|
||||
@@ -236,13 +229,7 @@ export async function finalizePreparedWorktree(
|
||||
const preparedHeadOutput = preparedResult.value.stdout
|
||||
if (preparedHeadOutput.trim() !== targetHead) {
|
||||
await gitExecFileAsync(
|
||||
[
|
||||
...windowsLongPathGitArgs(preparedPath),
|
||||
...worktreeCheckoutGitArgs(options),
|
||||
'reset',
|
||||
'--hard',
|
||||
targetHead
|
||||
],
|
||||
[...windowsLongPathGitArgs(preparedPath), 'reset', '--hard', targetHead],
|
||||
gitExecOptions(preparedPath, finalizeGitOptions)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
gitlabMergeRequestHeadLocalRef,
|
||||
reviewHeadRemoteRefComponent
|
||||
} from './review-head-tracking-ref'
|
||||
import { worktreeCheckoutGitArgs } from './worktree-checkout-config'
|
||||
|
||||
const execFileAsync = promisify(execFile)
|
||||
const image = process.env.ORCA_GIT_COMPAT_IMAGE
|
||||
@@ -112,48 +111,6 @@ describeBinaryCompatibility('real Git binary compatibility', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('materializes parallel checkouts with a serial fallback before Git 2.32', async () => {
|
||||
await runGit(['worktree', 'add', '--detach', 'parallel-source', 'HEAD'])
|
||||
await Promise.all(
|
||||
Array.from({ length: 16 }, (_, i) =>
|
||||
writeFile(join(repoPath, 'parallel-source', `parallel-${i}.txt`), `file ${i}\n`)
|
||||
)
|
||||
)
|
||||
await runGit(['-C', 'parallel-source', 'add', '.'])
|
||||
await runGit(['-C', 'parallel-source', 'commit', '-qm', 'parallel fixture'])
|
||||
const head = (await runGit(['-C', 'parallel-source', 'rev-parse', 'HEAD'])).stdout.trim()
|
||||
await runGit(['worktree', 'add', '--detach', '--no-checkout', 'parallel-wt', head])
|
||||
try {
|
||||
const result = await runGit(
|
||||
[
|
||||
'-C',
|
||||
'parallel-wt',
|
||||
...worktreeCheckoutGitArgs({}, 'darwin'),
|
||||
'-c',
|
||||
'checkout.thresholdForParallelism=0',
|
||||
'reset',
|
||||
'--hard',
|
||||
'HEAD'
|
||||
],
|
||||
{ GIT_TRACE2_EVENT: '1' }
|
||||
)
|
||||
expect(result.stderr.includes('checkout--worker')).toBe(supports(2, 32))
|
||||
expect(
|
||||
(await readFile(join(repoPath, 'parallel-wt', 'tracked.txt'), 'utf8')).replaceAll(
|
||||
'\r\n',
|
||||
'\n'
|
||||
)
|
||||
).toBe('compatibility\n')
|
||||
expect((await runGit(['-C', 'parallel-wt', 'status', '--porcelain'])).stdout).toBe('')
|
||||
await expect(
|
||||
runGit(['config', '--local', '--get', 'checkout.workers'])
|
||||
).rejects.toMatchObject({ code: 1 })
|
||||
} finally {
|
||||
await runGit(['worktree', 'remove', '--force', 'parallel-wt'])
|
||||
await runGit(['worktree', 'remove', '--force', 'parallel-source'])
|
||||
}
|
||||
})
|
||||
|
||||
it('quietly distinguishes present and absent branch refs', async () => {
|
||||
const head = (await runGit(['rev-parse', 'HEAD'])).stdout.trim()
|
||||
await runGit(['branch', 'quiet-probe-present', head])
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { worktreeCheckoutGitArgs } from './worktree-checkout-config'
|
||||
|
||||
describe('worktree checkout concurrency', () => {
|
||||
it('bounds native Mac checkout workers without changing other execution hosts', () => {
|
||||
expect(worktreeCheckoutGitArgs({}, 'darwin')).toEqual(['-c', 'checkout.workers=4'])
|
||||
expect(worktreeCheckoutGitArgs({ wslDistro: 'Ubuntu' }, 'darwin')).toEqual([])
|
||||
expect(worktreeCheckoutGitArgs({}, 'win32')).toEqual([])
|
||||
expect(worktreeCheckoutGitArgs({ wslDistro: 'Ubuntu' }, 'win32')).toEqual([])
|
||||
expect(worktreeCheckoutGitArgs({}, 'linux')).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
export function worktreeCheckoutGitArgs(
|
||||
options: { wslDistro?: string } = {},
|
||||
platform: NodeJS.Platform = process.platform
|
||||
): string[] {
|
||||
// Four workers halved native Mac checkout time; Git before 2.32 ignores this config.
|
||||
return platform === 'darwin' && !options.wslDistro ? ['-c', 'checkout.workers=4'] : []
|
||||
}
|
||||
Reference in New Issue
Block a user