diff --git a/docs/reference/git-compatibility.md b/docs/reference/git-compatibility.md index bc75543ac0f..1e19860385e 100644 --- a/docs/reference/git-compatibility.md +++ b/docs/reference/git-compatibility.md @@ -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 diff --git a/src/main/git/add-sparse-worktree.test.ts b/src/main/git/add-sparse-worktree.test.ts index c31b8de85cf..2541b822438 100644 --- a/src/main/git/add-sparse-worktree.test.ts +++ b/src/main/git/add-sparse-worktree.test.ts @@ -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', diff --git a/src/main/git/worktree-add-creation-config.test.ts b/src/main/git/worktree-add-creation-config.test.ts index eaa76f37083..ff44ca7ac6d 100644 --- a/src/main/git/worktree-add-creation-config.test.ts +++ b/src/main/git/worktree-add-creation-config.test.ts @@ -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', diff --git a/src/main/git/worktree-add-local-base-refresh.test.ts b/src/main/git/worktree-add-local-base-refresh.test.ts index a684594291b..1ba2e6c16b8 100644 --- a/src/main/git/worktree-add-local-base-refresh.test.ts +++ b/src/main/git/worktree-add-local-base-refresh.test.ts @@ -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', diff --git a/src/main/git/worktree-add-local-base-suggestion.test.ts b/src/main/git/worktree-add-local-base-suggestion.test.ts index b40d65d8955..3b449c339f6 100644 --- a/src/main/git/worktree-add-local-base-suggestion.test.ts +++ b/src/main/git/worktree-add-local-base-suggestion.test.ts @@ -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', diff --git a/src/main/git/worktree-add.ts b/src/main/git/worktree-add.ts index f36f2501787..380f3a3cc34 100644 --- a/src/main/git/worktree-add.ts +++ b/src/main/git/worktree-add.ts @@ -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') diff --git a/src/main/git/worktree-create-preparation.ts b/src/main/git/worktree-create-preparation.ts index b42771353fa..78713957690 100644 --- a/src/main/git/worktree-create-preparation.ts +++ b/src/main/git/worktree-create-preparation.ts @@ -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) ) } diff --git a/src/shared/git-binary-compatibility.test.ts b/src/shared/git-binary-compatibility.test.ts index e7ae0bc8797..fb8161b9f90 100644 --- a/src/shared/git-binary-compatibility.test.ts +++ b/src/shared/git-binary-compatibility.test.ts @@ -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]) diff --git a/src/shared/worktree-checkout-config.test.ts b/src/shared/worktree-checkout-config.test.ts deleted file mode 100644 index 01cd98eee39..00000000000 --- a/src/shared/worktree-checkout-config.test.ts +++ /dev/null @@ -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([]) - }) -}) diff --git a/src/shared/worktree-checkout-config.ts b/src/shared/worktree-checkout-config.ts deleted file mode 100644 index ce705f80241..00000000000 --- a/src/shared/worktree-checkout-config.ts +++ /dev/null @@ -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'] : [] -}