Fix .git/config lock race when creating worktrees concurrently#794
Merged
Merged
Conversation
`git worktree add -b <branch> <path> origin/main` auto-writes branch
tracking config (branch.<name>.{remote,merge}) into .git/config, which
takes the repo-wide config lock. When two worktree agents are created
against the same repo at the same instant, the second `worktree add`
loses the lock race and dies:
error: could not lock config file .git/config: File exists
error: unable to write upstream branch configuration
git treats that as fatal (exit 255) and fails the whole command, so the
agent-create API returns a 500. Surfaced as an intermittent E2E failure
in worktree.spec.ts whose setup creates several worktree agents in
parallel.
Fix: pass --no-track to `git worktree add` so it no longer writes
tracking config — that removes the only .git/config write from the
non-idempotent command, so it can't lose the race. Upstream is still set
explicitly right after via `git branch --set-upstream-to` (unchanged),
which already tolerates exit 1/128; git returns exit 1 when that write
hits a contended lock, and a missing upstream degrades correctly to
origin/<base> in worktree-status and base-ref, so creation succeeds
either way.
Adds regression tests: `worktree add` carries --no-track, and creation
succeeds when the upstream write is blocked by a contended config lock
(exit 1 + lock stderr), matching real git behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This was referenced Jul 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
git worktree add -b <branch> <path> origin/mainauto-writes branch tracking config (branch.<name>.{remote,merge}) into.git/config, which takes the repo-wide config lock. When two worktree agents are created against the same repo at the same instant, the secondworktree addloses the lock race:git treats this as fatal (exit 255) and fails the whole command, so
POST /api/v1/agentsreturns a 500. Surfaced as an intermittent E2E failure inworktree.spec.ts(whose setup creates several worktree agents in parallel) that aborted the E2E run. Root-caused from the preserved Playwright trace (500 body contained the config-lock error).Fix
Pass
--no-tracktogit worktree addso it no longer writes tracking config. That removes the only.git/configwrite from the non-idempotent command, so it can't lose the race. Upstream is still set explicitly right after viagit branch --set-upstream-to(unchanged), which already tolerates exit 1/128 — git returns exit 1 when that write hits a contended lock, and a missing upstream degrades correctly toorigin/<base>inworktree-status.tsandbase-ref.ts, so creation succeeds either way. The end-state upstream (origin/main) is identical to git's auto-track output.Tests
worktree addcarries--no-trackand sets upstream explicitly.worktree addcommand assertions for the new--no-trackflag.Validation
pnpm run check✓pnpm run test✓ (server 2281 pass / 8 skip, +2 net new tests)pnpm run test:e2e✓ (168 passed / 13 skipped; previously-failingworktree.spec.ts:480now green)A review agent flagged that an earlier draft's retry loop was dead code (git returns exit 1, which
allowedExitCodesswallows before any throw); this PR drops the retry in favor of the deterministic--no-trackfix per that feedback.🤖 Generated with Claude Code