fix(server): git 2.56 broken-gitfile worktrees count as non-repositories again#33423
Problem
Git 2.56 changed what it prints when a worktree's .git gitfile points at a directory that no longer exists. Older releases print fatal: not a git repository: /missing-git-directory. Git 2.56 prints fatal: gitfile does not point to a valid repository: <path>/.git, from READ_GITFILE_ERR_NOT_A_REPO in git's setup.c.
The server decides "this directory is not a repository" by looking for not a git repository in stderr. Three places make that check:
isNonRepositoryGitStderrinapps/server/src/vcs/GitVcsDriverCore.ts- an inline copy in
StorageCleanup.branchChanged(apps/server/src/storageCleanup.ts) - an inline copy in
isNotGitRepositoryError(apps/server/src/git/GitManager.ts)
With git 2.56, none of the three recognises a worktree whose gitdir has gone. Expected behaviour: storage cleanup keeps such a managed worktree as "Repository or branch changed". Actual behaviour: it reports the worktree as failed, with the raw gitfile does not point to a valid repository line as the reason. GitManager has the same problem: its status and PR lookups fail on that folder instead of using their existing non-repository fallback.
Reproduction: the existing live test in storageCleanup.test.ts corrupts a worktree's .git to gitdir: /missing-git-directory and expects cleanup to keep the worktree. The test passes with older git and fails with git 2.56.0, which GitHub-hosted ubuntu-24.04 runners now ship. We hit this failure on hosted CI in a fork.
Change
isNonRepositoryGitStderris exported and now matches either phrase, ignoring case.storageCleanup.tsandGitManager.tscall the shared classifier instead of keeping their own copies. The three checks then always agree, and all three change together if git rewords the message again.- Nothing changes for real repositories. The only new case treated as non-repository is the one where git itself says the gitfile does not point to a valid repository. Other gitfile errors such as
invalid gitfile formatstill fail, and a test row covers that.
Scope and approval
This is a small, focused fix for an obvious bug, so it qualifies without a prior issue. It is one defect: git reworded a message the server already classifies. There is no new behaviour; git 2.56 simply reaches the existing non-repository handling again. All four touched files serve that one fix: the classifier, its two inline duplicates and its test.
Verification
- New table test
isNonRepositoryGitStderrinGitVcsDriverCore.test.tshas 4 rows that must classify as non-repository (both wordings, plus upper case) and 4 that must not (empty, unknown revision,index.lockexists, invalid gitfile format).vp test run src/vcs/GitVcsDriverCore.test.ts -t isNonRepositoryGitStderr: 8 passed. Without the fix, the 2 gitfile rows fail.
- Regression comparison on Windows 11 with git 2.52, current
main:vp test run src/vcs/GitVcsDriverCore.test.ts src/storageCleanup.test.ts src/git/GitManager.test.ts- on
main(b8c2cfad6b): 37 failed / 512 passed - with this change: 37 failed / 520 passed (the 8 new rows)
- The 37 failures are identical by name in both runs. They are pre-existing live-git failures in this Windows environment and unrelated to this change.
- on
pnpm run typecheck(apps/server) passes, and the commit hooks'vp fmt,vp lintandknippass.- Not checked locally: git 2.52 cannot produce the 2.56 message, so the end-to-end
storageCleanupworktree test with git 2.56 is checked by CI on Linux. The same change, without theGitManagerreuse, passed all 25 checks on GitHub-hosted runners with git 2.56 in the fork (Ali-Al1/t3code#4), where the storageCleanup test had failed before it.
Review history
- The change was first reviewed in the fork PR linked above: two independent model review rounds, all checks green on hosted runners with git 2.56.
- Porting: cherry-picked cleanly onto current
main. None of the touched files had changed since the fork's base. - Added during the port:
GitManager.isNotGitRepositoryErrorhad a third copy of the same check and now uses the shared classifier. The fork review did not cover this step. - A separate adapter change from the same fork, gateway credential-pool reset parsing, was assessed for upstream and not proposed: it relies on one gateway configuration's message order.
Code written by Claude Opus 5.5 in Claude Code.
🤖 Generated with Claude Code
Checks
Added 1 commit
- fix(server): treat git 2.56 broken-gitfile stderr as non-repositorybb485ef
Approvability
Verdict: Approved at bb485ef
Macroscope's review found this PR approvable — Recognizes Git 2.56's broken-gitfile diagnostic using existing non-repository handling. Status reads degrade gracefully, while storage cleanup retains affected worktrees rather than deleting them.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
Walkthrough
-
The shared Git stderr classifier recognizes standard “not a git repository” messages and missing-target gitfile errors.
GitManagerandstorageCleanupuse it to identify non-repository errors. Tests cover recognized messages and exclusions.Changes: Git error classification
Layer / File(s) Summary Classifier, tests, and callers
apps/server/src/vcs/GitVcsDriverCore.ts,apps/server/src/vcs/GitVcsDriverCore.test.ts,apps/server/src/git/GitManager.ts,apps/server/src/storageCleanup.tsThe exported isNonRepositoryGitStderrclassifier recognizes two diagnostic phrases without case sensitivity. Tests cover positive and negative cases. Both callers use the shared classifier.Estimated code review effort: 2 (Simple) | ~8 minutes
Change: Bug fix
Suggested reviewers:
juliusmarminge,only21mil,t3dotgg
Merge Risk: External image Low · up to bb485
-
A repository with the diagnostic phrase in its path can be reported as a non-repository during an index-lock error. This narrow, recoverable issue does not block merge.
Pre-merge checks: Passed 4
-
Check name Status Explanation Title check Passed The title names the main change: Git 2.56 broken-gitfile worktrees are treated as non-repositories again. The changeset exports and uses the shared isNonRepositoryGitStderr classifier to match Git 2.5… Description check Passed The description follows the template's Problem, Change, Scope and approval, and Verification sections. It explains the Git 2.56 stderr change, the three duplicated checks, and the fix. Scope is justif… Linked Issues check Passed Check skipped because no linked issues were found for this pull request. Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request. Full details: Title check
-
Explanation
The title names the main change: Git 2.56 broken-gitfile worktrees are treated as non-repositories again. The changeset exports and uses the shared isNonRepositoryGitStderr classifier to match Git 2.56's new 'gitfile does not point to a valid repository' message, so the title matches the change. It is slightly long at 78 characters but conventional and specific.
Full details: Description check
-
Explanation
The description follows the template's Problem, Change, Scope and approval, and Verification sections. It explains the Git 2.56 stderr change, the three duplicated checks, and the fix. Scope is justified as a small, focused fix of an obvious bug. Verification lists focused tests, a Windows regression comparison, typecheck and lint results, and states what was not checked locally. The template's agent-model line is present ('Code written by Claude Opus 5.5 in Claude Code'). The description also adds a review history section, which is extra but does not break the template.
-
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
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: main
- File: .coderabbit.config.ts
- Commit: b8c2cfa
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Advanced
- Run ID:
b069ffd6-0cc5-468b-b770-b57bdfa2dd18
External image Commits
-
Reviewing files that changed from the base of the PR and between b8c2cfad6b3363c4da144a859073b41ec77579ab and bb485efc4dfecad3ae2be12ad2a972e5b6dd48d9.
External image Files selected for processing: 4
-
apps/server/src/git/GitManager.tsapps/server/src/storageCleanup.tsapps/server/src/vcs/GitVcsDriverCore.test.tsapps/server/src/vcs/GitVcsDriverCore.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
External image Recent review info
-
External image Run configuration
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: main
- File: .coderabbit.config.ts
- Commit: b8c2cfa
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Advanced
- Run ID:
b069ffd6-0cc5-468b-b770-b57bdfa2dd18
External image Commits
-
Reviewing files that changed from the base of the PR and between b8c2cfad6b3363c4da144a859073b41ec77579ab and bb485efc4dfecad3ae2be12ad2a972e5b6dd48d9.
External image Files selected for processing: 4
-
apps/server/src/git/GitManager.tsapps/server/src/storageCleanup.tsapps/server/src/vcs/GitVcsDriverCore.test.tsapps/server/src/vcs/GitVcsDriverCore.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
-
Thanks, Ali-Al1, for diagnosing and testing this! Closing as a duplicate of #26359 by Yarden-zamir, which covers the same Git 2.56 broken-gitfile handling and includes additional end-to-end regression evidence.
Reopening this focused fix: it applies cleanly to current main, while the earlier #26359 now conflicts. Thanks, Ali-Al1 and Yarden-zamir, for your work on this.
Note
Written by gpt-6.1-sol on behalf of Maria
Verified in a real dev environment
verified unchanged head bb485efc4dfecad3ae2be12ad2a972e5b6dd48d9 on linux with real git 2.56.0, built from the upstream release. reproduced on github/main at 4c924ff4e6 first, using a separate worktree. only one dev server ran at a time.
used playwright and /usr/bin/google-chrome to add a real repository, create a managed worktree, and send real codex gpt-6.1-sol turns through the web composer. the first turn created evidence.txt; a second turn on the pr read and updated it. both completed.
changed the app-created worktree's .git to point at a missing directory, then clicked settings > maintenance > delete now with unchanged-worktree cleanup enabled:
| 1 | main: 0 removed, 0 kept, 1 failed |
| 2 | gitfile does not point to a valid repository |
| 3 | pr: 0 removed, 1 kept |
| 4 | repository or branch changed |
the same worktree and file survived. the actual client subscribeVcsStatus response on the pr returned isRepo: false, refName: null, and remote: null.
neighbor checks: an invalid gitfile still reported a failure. restoring the valid gitfile restored branch/status display and the untracked file; cleanup kept it with has uncommitted changes (1 file).
remote blacksmith check: the existing GitVcsDriverCore, storageCleanup, and GitManager suites passed, 561 tests across 3 files. no source changes or pushes were needed.
main: broken gitfile makes cleanup fail
pr: the same broken worktree is kept
real codex turns and restored git changes
sampled cleanup interaction: delete now retains the broken worktree
Not verified
native desktop/mobile clients, macos/windows, and remote/tunnel connections were not exercised on this linux vm. external hosting-provider pr lookup was not exercised because the verification repository has no remote.
an existing limitation remains on both main and this head: automatic settlement logs a GitManager.branchPullRequest.remotes non-repository warning for the broken worktree. the cleanup regression above is fixed; this verification does not claim that separate lookup path is fixed.