perf(server): batch worktree branch allocation and avoid path collisions#32934

merged4
main
GitHub fork: t3/worktree-branch-allocation
opened1d agobyWWout Stiens
View on GitHubTwo-way sync enabledPR last imported 21h ago

Problem

Automatic worktree branch allocation spawned Git for each occupied suffix. Generated checkout folders also collided for feat/a versus feat-a and repositories with the same basename.

Change

Read branch availability once, retain ancestor/descendant conflicts and bounded suffix allocation, then let Git's atomic ref operation decide concurrent creation. Reserve case variants for case-insensitive filesystems. New generated folders use a bounded Unicode prefix plus a digest of the shared Git directory and branch. Existing registered paths and explicit paths remain unchanged. All new generated folders, including short names, now include the digest.

Standard change: allocation and filesystem identity behavior, scoped to the existing driver and its tests. No UI, deletion, attachment, lifecycle module, or registry changes.

Scope and approval

This is limited to branch allocation and generated checkout-path identity. The new default folder convention requires upstream maintainer approval, as Macroscope notes; that approval is not claimed here. Existing registered and explicitly supplied paths remain unchanged. The worktree assessment explains the direction. GitCafe issue publication failed, so no tracking issue or approval comment is invented. Leave this PR open and unmerged pending the maintainer's decision.

Verification

  • Final rebased head: 874fbd5924c5071f7fbad0cdeb8511ec0a4acf10, target 6417151c09. All four patches compare unchanged to reviewed/evidenced head 5c18a1bbef4e90750163e34b0572647b7dc02ac3 via git range-diff; upstream changes were unrelated web and Codex adapter work.
  • pnpm exec vp run check:changed passes on the rebased head: format, lint, both knip checks, GraphQL, three affected typechecks, 247 tests in two files. The driver suite independently passes all 245 tests. No repo-wide checks run; hosted CI remains pending.
  • Actual temporary Git repositories cover ref ancestry, exhaustion, exact/option-like names, Unicode byte bounds, four collision-free generated paths, and concurrent creators pointing at distinct commits. Old path allocation fails the new collision/byte-bound tests; the pre-fix allocator fails three case-variant rows. Scratch mutations prove test sensitivity for ancestry, exhaustion, concurrency, output limits and path behavior; 13 focused cases pass afterward. Legacy registered path and contents survive new checkout creation. Oversized stdout proof is synthetic; path/ref scenarios use actual Git.
  • Proof auditor: PASS, no code-proof gaps, unchanged rebase preserves evidence.

Measurements

Original exact base 8e6a7323050ea8d2891f745f7e624e84f9fd8d9a was measured before edits, and the identical harness was repeated against the final reviewed source. Linux 7.0.0-42-generic, AMD Ryzen 9 7950X, Node 24.19.0, Git 2.53.0. Each of five samples per revision/mode/occupancy creates a fresh repository and driver: one empty commit, no tracked files, remote or submodules, plus 0 or 20 occupied suffixes. No warm-driver claim; OS caches/load uncontrolled.

Commands use pnpm exec vp test run --config .local/worktree-management/benchmark.config.ts through an allocation-only local harness. It measures public renameBranch, then public createWorktree; explicit mode supplies a path, generated mode uses path: null and a managed directory. Repeated base aliases the exact-base driver into the same harness without moving the shared checkout. Git counts are actual driver-spawned subprocesses. Filesystem counts instrument stat/exists/readDirectory/realPath probes, not all kernel operations; SQL is absent. These are direct-driver empty-checkout workloads, not mounted UI or large-repository throughput measurements.

Times are median [min, max] milliseconds:

RunOccupiedNaming msCheckout msCombined msGit naming / checkout / combinedFS naming / checkoutSQL
Original base029.79 [28.87, 40.39]20.98 [17.18, 22.71]49.91 [47.73, 63.19]9 / 5 / 146 / 30
Original base20204.53 [161.02, 267.68]22.20 [19.64, 26.44]230.98 [182.67, 292.17]49 / 5 / 546 / 30
Repeated base026.99 [24.94, 31.24]19.43 [17.40, 20.13]46.43 [42.38, 51.42]9 / 5 / 146 / 30
Repeated base20147.19 [142.04, 157.94]16.77 [15.91, 20.46]163.11 [158.82, 178.42]49 / 5 / 546 / 30
Final head021.64 [21.57, 27.08]17.91 [14.80, 18.14]39.56 [36.38, 45.09]8 / 5 / 136 / 30
Final head2022.70 [20.94, 23.34]16.81 [15.86, 18.70]38.85 [38.57, 41.72]8 / 5 / 136 / 30
Generated base025.52 [23.62, 27.31]18.27 [15.54, 20.17]45.36 [39.16, 47.36]9 / 5 / 146 / 30
Generated base20145.30 [142.71, 149.04]17.68 [15.31, 19.42]162.75 [160.40, 164.72]49 / 5 / 546 / 30
Generated head024.11 [22.58, 29.27]22.17 [19.68, 23.90]45.28 [43.81, 53.21]8 / 6 / 146 / 50
Generated head2021.50 [21.45, 27.41]20.52 [18.43, 22.57]44.07 [39.89, 47.93]8 / 6 / 146 / 50

With 20 occupied suffixes, naming drops from 49 to 8 Git processes. Generated checkout adds one Git identity read and two filesystem probes, so combined generated-mode processes drop 54 to 14 at 20 suffixes and stay 14 at zero. No blanket checkout-speedup claim.

Controlled timing was attempted with fleet-boat-bench run --rounds 5 against the exact base/head, using the same harness via --prepare. It failed before timing during bundle import: missing object 10581521d27d14d8f0a15dfc24525efbd52ae057, then bench.bundle did not send all necessary objects (exit 1). There is no controlled timing or instructions change line; local timings above are descriptive only.

Limits and review decisions

Native Windows/macOS filesystem behavior is unverified; Linux tests prove component bounds and conservative case reservation. JavaScript lowercasing is not every filesystem's Unicode case folding. Digest collision remains theoretically possible with 64 bits. Ref listings above 16 MiB fail safely rather than allocating from partial data.

Kept nit: a case-only automatic rename of its own branch may receive a suffix. The non-exact caller renames temporary launch branches; manual exact-name rename bypasses allocation. Declined the null common-directory nit because it occurs outside repositories, where worktree creation fails anyway. Follow-ups outside scope: shared branch allocator rule differences (packages/shared/src/git.ts:72) and the existing 1 MiB listLocalBranchNames output cap in the driver.

Council review

ReviewerRound 1Round 2
GPT 6.1 Sol9/109/10
Claude Opus 5.58/109/10
Grok 4.79/109/10

Round-two case reservation and stronger assertions resolve all should-fix findings. Council reviewed the identical patches before the clean rebase; proof audit confirmed coverage survives it. Local cubic on the final rebased head reports zero issues (repository context unavailable for the GitCafe origin). The prior automatic self-rename P3 nit is disclosed above. GitCafe issue publishing is unavailable; the approved local ticket is used without inventing an issue or upstream closing reference.

Created with GPT 6.1 Sol (lead, build, evidence, proof audit and review), Claude Opus 5.5 (trim/simplify and review), and Grok 4.7 (review), through T3 Code and the Codex, Claude and Grok harnesses.

Checks

23 successful · 14 skipped · 1 neutral
All checks passed
874fbd5

Added 4 commits

  • refactor(server): trim branch allocation and generated path naming17b54fd
  • fix(server): batch branch allocation and avoid worktree path collisions313ed5c
  • fix(server): reserve case variants during branch allocation874fbd5
  • chore: credit branch allocation reviewersa46f47f
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The PR batches branch collision checks and changes automatically generated worktree directory names to include a repository-specific hash. Human confirmation is needed for the changed default path convention; explicit paths and existing worktree locations are unaffected.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The change updates branch-name collision handling and generated worktree directory naming. Tests cover case variants, suffix exhaustion, concurrent branch creation, path uniqueness across repositories, and UTF-8 byte limits.

Changes: VCS naming

Layer / File(s)Summary
Branch-name collision handling
apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts
Branch selection enumerates local refs with a 16 MiB output limit. It compares names case-insensitively, handles blocked parent paths, and tries suffixes through -100. Tests cover case variants, suffix exhaustion, and concurrent branch creation.
Generated worktree directory names
apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts
Generated directory names include a 16-character SHA-256 prefix derived from the Git common directory and target branch. Tests check path uniqueness and a 40-byte UTF-8 limit.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related issues

  • pingdotgg/t3code issue 29515 — The new directory naming distinguishes branch spellings that previously could map to the same folder. The issue’s orphaned-branch and retry behavior is not changed here.

Possibly related PRs

Suggested reviewers: marcodotio, juliusmarminge, macroscopeapp

Merge Risk: External image Minimal · up to 874fb

The change batches branch-name lookups and gives generated worktree folders unique names. No concrete defect was found, so it looks safe to merge after normal CI.

Pre-merge checks: Passed 4

Check nameStatusExplanation
Title checkPassedThe title "perf(server): batch worktree branch allocation and avoid path collisions" matches the main change. The raw summary and objectives show batched branch enumeration in resolveAvailableBranchNa…
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Description checkPassedThe description is detailed and covers most template sections. Problem and Change are clearly stated. Scope and approval explains that the new default folder convention needs upstream maintainer appro…
Full details: Title check

Explanation

The title "perf(server): batch worktree branch allocation and avoid path collisions" matches the main change. The raw summary and objectives show batched branch enumeration in resolveAvailableBranchName and a new collision-resistant generated worktree folder name with a SHA-256 digest. The title is a conventional commit and names both the performance change and the path collision fix. The title is long at 72 characters, but it stays specific and readable.

Full details: Description check

Explanation

The description is detailed and covers most template sections. Problem and Change are clearly stated. Scope and approval explains that the new default folder convention needs upstream maintainer approval and that this approval is not claimed; it also says the PR should stay open and unmerged. Verification is extensive, with commands, test counts, and a benchmark table. Two gaps remain: the template asks for a link to a triaged issue or a maintainer-approval comment, and the author says none exists. The description also lacks an explicit statement of the model and harness, although it names them in the closing line. The author's disclosure of the approval gap and the unverified platforms is candid. The description is mostly complete, so the check passes, but the approval gap should be surfaced to reviewers.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between 6417151c093e54dbba0e6c824c69d03983793b9a and 874fbd5924c5071f7fbad0cdeb8511ec0a4acf10.

External image Files selected for processing: 2

  • apps/server/src/vcs/GitVcsDriverCore.test.ts
  • apps/server/src/vcs/GitVcsDriverCore.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.