fix(server): git 2.56 broken-gitfile worktrees count as non-repositories again#33423

merged1
main
GitHub fork: fix/git-2.56-gitfile-nonrepo
opened2d agobyAAli-Al1
View on GitHubTwo-way sync enabledPR last imported 2h ago

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:

  • isNonRepositoryGitStderr in apps/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

  • isNonRepositoryGitStderr is exported and now matches either phrase, ignoring case.
  • storageCleanup.ts and GitManager.ts call 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 format still 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 isNonRepositoryGitStderr in GitVcsDriverCore.test.ts has 4 rows that must classify as non-repository (both wordings, plus upper case) and 4 that must not (empty, unknown revision, index.lock exists, 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.
  • pnpm run typecheck (apps/server) passes, and the commit hooks' vp fmt, vp lint and knip pass.
  • Not checked locally: git 2.52 cannot produce the 2.56 message, so the end-to-end storageCleanup worktree test with git 2.56 is checked by CI on Linux. The same change, without the GitManager reuse, 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.isNotGitRepositoryError had 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

24 successful · 16 skipped
All checks passed
bb485ef

Added 1 commit

  • fix(server): treat git 2.56 broken-gitfile stderr as non-repositorybb485ef
Synced from GitHub

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.

Synced from GitHub

Explain Change →

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. GitManager and storageCleanup use 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.ts
The exported isNonRepositoryGitStderr classifier 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 nameStatusExplanation
Title checkPassedThe 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 checkPassedThe 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 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.
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

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.ts
  • apps/server/src/storageCleanup.ts
  • 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; 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:

text
1main: 0 removed, 0 kept, 1 failed
2 gitfile does not point to a valid repository
3pr: 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

short runtime transcript

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.