Skip to content

fix(server): projects no longer show another repo's Git state when T3 starts inside a Git command - #28795

Open
only21mil wants to merge 5 commits into
pingdotgg:mainfrom
only21mil:fix/audit-m115
Open

only21mil wants to merge 5 commits into
pingdotgg:mainfrom
only21mil:fix/audit-m115

Conversation

@only21mil

@only21mil only21mil commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When T3 Code starts inside a Git command, every project's Git commands can run against the wrong repository. In a linked worktree, Git hooks and git rebase --exec export an absolute GIT_DIR (commit hooks also export GIT_INDEX_FILE). A T3 server started from there passes those variables to all of its Git subprocesses. Every project then shows that worktree's branch, status and repository identity, and checkpoints are written into it.

Reproduction: make two repositories, demo-project on feature/demo-project and inherited-other on wrong-repository-branch. Start the server with GIT_DIR=<inherited-other>/.git, then add demo-project. The sidebar labels it example/inherited-other and the branch picker shows wrong-repository-branch.

Change

gitProcessEnv in VcsProcess.ts builds the environment for a Git child process. It first unsets the repository selectors the server inherited (GIT_DIR, GIT_WORK_TREE, GIT_COMMON_DIR, GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY, GIT_ALTERNATE_OBJECT_DIRECTORIES, the same list #12181 clears, plus GIT_CEILING_DIRECTORIES), then applies the caller's env, then the existing safe.bareRepository=explicit config from #20440. Selectors a caller sets on purpose still win, such as a checkpoint's private GIT_INDEX_FILE or worktree removal's bound GIT_DIR.

It is used at the three places that spawn Git and already added the bare-repository config: GitVcsDriverCore, VcsProcess (checkpoints, file listing, source-control CLIs) and RepositoryIdentityResolver.

The checkpoint commit env no longer spreads process.env itself, because that spread re-added the inherited selectors as if the caller had set them. #12181's nested-repository probe no longer needs its own cleared env, so that block is removed.

Other GIT_* variables are left alone, including config, auth, SSH and locale. Provider CLIs and terminals still inherit the server's environment unchanged.

Scope and approval

This is a small, focused fix for an obvious bug: Git commands for one project run against a different repository. It uses the CONTRIBUTING exception for obvious bugs, with no issue or discussion. It extends the narrow fix in #12181 to the shared Git spawn paths and clears only the variables #12181 clears.

Maintainers to confirm: the scope covers Git subprocesses only. Provider and terminal environments are unchanged.

Verification

Tests, on macOS with git 2.56. Each fails on main and passes on this branch:

  • GitVcsDriverCore.test.ts "ignores repository selectors inherited by the server". On main, status reports the other repo's branch: expected 'other-repository' to equal 'main'. It also covers a private GIT_INDEX_FILE commit context and an explicit bare GIT_DIR.
  • GitVcsDriver.test.ts "checkpoint capture ignores repository selectors inherited by the server" extends the fix(server): checkpoint workspaces with empty nested repositories #12181 test. The inherited GIT_DIR, GIT_WORK_TREE and GIT_INDEX_FILE now point at a second repository. On main, the checkpoint ref is written there instead. It also checks the second repository is untouched, the fix(server): checkpoint workspaces with empty nested repositories #12181 nested-HEAD exclusion still holds, and an explicit bare GIT_DIR still works on this path.
  • RepositoryIdentityResolver.test.ts "ignores repository selectors inherited by the server". On main it fails with expected 'github.com/t3tools/other' to be 'github.com/t3tools/t3code'.

Runs:

  • vp run check:changed 1d626d02d95f9a2343553f6498037ee82290d304: format, lint, knip and typecheck pass. Tests: 321 passed, 4 failed.
  • vp test run on src/vcs, src/sourceControl, src/workspace, src/checkpointing and the resolver test: 460 passed, 4 failed.
  • The 4 failures are the same in both runs and also fail on unmodified main on this machine. Three come from a global url.insteadOf rewrite in this machine's Git config, and one from macOS /var vs /private/var temp paths. With GIT_CONFIG_GLOBAL=/dev/null and a resolved TMPDIR, they pass.

Which Git contexts set these, checked with a hook that prints them (git 2.56): in a linked worktree, pre-commit, post-commit, post-checkout and git rebase --exec export an absolute GIT_DIR, and commit hooks an absolute GIT_INDEX_FILE. In a primary checkout, commit hooks export only a relative GIT_INDEX_FILE.

UI, on each client. I ran the dev server with GIT_DIR set to the second repository and a fresh, isolated database, once on main and once on this branch. Every client shows the same synthetic demo-project (a free replay turn). Machine names are blanked out.

Web, before on main: the sidebar and thread details show the other repository's name and branch.

Web before: demo-project labelled example/inherited-other on wrong-repository-branch

Web, after on this branch: the project shows its own name and feature/demo-project.

Web after: demo-project labelled demo-project on feature/demo-project

Desktop, iOS and Android, with the same server runs:

Before (main) After (this branch)
Desktop Desktop before Desktop after
iOS iOS before iOS after
Android Android before Android after

Not checked

  • Windows. Matching the variable names case-insensitively follows gitConfigEnv, but it was not run on Windows.
  • Git versions other than 2.56.

Prior PRs

Generated with Claude Opus 5.5 and GPT-6.1 Terra and GPT-6.1 Sol in T3 Code Nightly

…rited

A T3 server started from a Git hook or `git rebase --exec` in a linked
worktree inherits GIT_DIR and GIT_INDEX_FILE, and every project's Git
commands then read and write that worktree instead of the project.

gitProcessEnv builds the Git child environment at the three Git spawn
sites (GitVcsDriverCore, VcsProcess, RepositoryIdentityResolver): it
unsets inherited repository selectors, then applies the caller's env, so
deliberate private-index and bare-repository overrides still win. The
nested-repository probe from pingdotgg#12181 no longer needs an env of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 1, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 7ba2d9a

Macroscope's review found this PR approvable — Git commands now ignore inherited repository selectors so each project uses its own repository rather than the server’s launch context. Explicit command overrides and existing bare-repository safeguards are preserved.

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

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Git subprocess environments now remove inherited repository-selection variables before applying caller-provided values. Repository identity resolution and checkpoint operations use this environment construction. Regression tests cover inherited selectors that point to another repository and explicit selection of a bare repository.

Changes: Git subprocess environment isolation

Layer / File(s) Summary
Build Git subprocess environments
apps/server/src/vcs/VcsProcess.ts, apps/server/src/vcs/GitVcsDriverCore.ts
gitProcessEnv removes inherited Git repository selectors, applies caller-provided environment values, and adds safe.bareRepository=explicit. VcsProcess.spawn and GitVcsDriverCore use it.
Use isolated environments for repository identity
apps/server/src/project/RepositoryIdentityResolver.ts, apps/server/src/project/RepositoryIdentityResolver.test.ts
Repository-root detection and remote discovery use gitProcessEnv. Tests cover identity resolution when inherited selectors point to another repository and set GIT_CEILING_DIRECTORIES for nested workspace resolution.
Keep checkpoint operations on the requested repository
apps/server/src/vcs/GitVcsDriver.ts, apps/server/src/vcs/GitVcsDriver.test.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts
Checkpoint HEAD checks no longer accept an environment override. Checkpoint commit environment construction no longer copies process.env, and nested-repository recovery no longer builds a sanitized environment. Tests check index and checkpoint-ref behavior when inherited selectors point elsewhere and confirm explicit bare-repository selection.

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

Change: Bug fix

Suggested reviewers: juliusmarminge, saphid

Merge Risk: Minimal · up to 5036c

The inherited Git discovery issue is addressed, and no actionable merge-blocking risk remains after normal checks.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title clearly describes the main fix: projects no longer use another repository’s Git state when T3 starts inside a Git command.
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.
Description check Passed The description covers the required Problem, Change, Scope and approval, and Verification sections. It gives reproduction steps, explains the fix and its scope, reports test results and limitations, a…
Full details: Description check

Explanation

The description covers the required Problem, Change, Scope and approval, and Verification sections. It gives reproduction steps, explains the fix and its scope, reports test results and limitations, and includes UI evidence. It also identifies the prior PRs and the agents used.

Finishing Touches

Generate unit tests (beta)

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

Run configuration

Commits

Reviewing files that changed from the base of the PR and between c7a1c4e and 5036c42.

Files selected for processing: 5

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

Limit details: You’ve used all 10 included reviews currently available.

@maria-rcks

maria-rcks commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by claude-opus-5-5 on behalf of Maria

Merged current main into this branch again without rebasing (c7a1c4e570). Main's HostProcess.Environment refactor (#31218) conflicted with this change in three files:

  • GitVcsDriver.ts: kept this PR's removal of the host-env spread in the checkpoint commit env and of nestedRepoEnv, since gitProcessEnv already clears inherited selectors.
  • GitVcsDriverCore.ts: the status env now spreads HostProcess.Environment (main's side) and then gitProcessEnv (this PR's side).
  • GitVcsDriver.test.ts: kept this PR's inherited-selector checkpoint test, which points GIT_DIR, GIT_WORK_TREE and GIT_INDEX_FILE at another repo.

No other behavior changes. The diff against main is still seven files. Blacksmith vp run check:changed github/main passed: format, lint, knip, GraphQL, three affected typechecks, and all 354 tests across five files.

Earlier history: merged main once before (66763a2be2). f4eca04c94 cleared inherited GIT_CEILING_DIRECTORIES before caller overrides, per review.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Fix comments: Fix CodeRabbit comments on this PR

Comment thread apps/server/src/vcs/VcsProcess.ts Resolved
maria-rcks and others added 3 commits November 3, 2026 04:22
# Conflicts:
#	apps/server/src/vcs/GitVcsDriver.test.ts
#	apps/server/src/vcs/GitVcsDriver.ts
#	apps/server/src/vcs/GitVcsDriverCore.ts
Git child processes keep main's LANGUAGE=C for git commands in VcsProcess,
now passed through gitProcessEnv alongside the caller's env.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@only21mil

Copy link
Copy Markdown
Contributor Author

Note

🤖 Opus 5.5 replying on behalf of Victor.

Merged current main into this branch to clear the conflict, as one merge commit with no rebase: 5036c42.

The three "ignores repository selectors inherited by the server" tests still fail with main's server files and pass on the merge. vp run check:changed passes, and so do the vcs, sourceControl, workspace, checkpointing, project and git suites (844 tests).

Fresh captures from the merged code, with the server started under another repository's GIT_DIR:

Before (main) After (this branch)
Web Web before Web after
Desktop Desktop before Desktop after
iOS iOS before iOS after
Android Android before Android after

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants