Summary
In a linked git worktree (git worktree add), react-doctor --staged refuses to scan and exits 1, reporting that ~60 config files differ between the index and the worktree — including git-ignored node_modules/**/package.json manifests that can never be staged.
The trigger is the GIT_DIR environment variable, which git exports to hooks only from a linked worktree, where it points at <main>/.git/worktrees/<name> rather than a real .git directory. Because git exports it for every hook invocation, this makes a --staged pre-commit hook fail on every commit made from a worktree.
This is adjacent to but distinct from #1501 and #1620, both of which are closed — see "Relationship to existing issues" below.
Repro
git init main && cd main
echo x > a.txt && git add -A && git commit -m init
git worktree add ../linked -b lk && cd ../linked
# install react-doctor, stage a source file, then:
GIT_DIR="$(git rev-parse --git-dir)" npx react-doctor . --staged --blocking error
GIT_DIR is set explicitly here to reproduce outside a hook; inside a real pre-commit hook git sets it for you.
Expected
Scans the staged files, exactly as it does when GIT_DIR is unset.
Actual
Cannot scan staged files while configuration differs between the index and worktree:
app.config.ts, ..., node_modules/@sentry/core/package.json, node_modules/zod/package.json,
..., tsconfig.json. Stage or restore those files, then rerun react-doctor --staged.
Exit 1, zero findings reported. In a pre-commit hook this surfaces as a false "error-severity findings" failure.
Version boundary (measured, same repo, same index, same command)
| Version |
With GIT_DIR set |
Without |
| 0.7.2 |
scans normally |
scans normally |
| 0.8.1 |
refuses |
scans normally |
| 0.9.11 (latest) |
refuses |
scans normally |
| 0.9.11-dev.8606ddd |
refuses |
scans normally |
So it is a regression introduced somewhere in 0.8.x. 0.9.11-dev.8606ddd was published ~9 minutes after #1620 was closed, and still reproduces, which is what convinced me this is a separate defect rather than the same one.
Layout boundary
A main worktree is unaffected at every version. Verified on git 2.50.1 that git exports GIT_DIR to hooks only from a linked worktree — from a main worktree it is not exported at all, from either the repo root or a subdirectory. That is why this only bites worktree users.
Scope boundary
Only --staged is affected. --scope changed --base origin/main behaves identically with and without GIT_DIR.
Relationship to existing issues
If you consider this a duplicate of either, happy to close — but the GIT_DIR-set / GIT_DIR-unset asymmetry on a post-fix build seemed worth reporting separately.
Workaround
Wrapping the hook invocation with env -u GIT_DIR restores correct behaviour, and is a no-op for main-worktree users since git does not export the variable there:
env -u GIT_DIR ./node_modules/.bin/react-doctor apps/mobile --staged --blocking error
I verified the workaround does not weaken the gate: with GIT_DIR unset in a linked worktree, a staged file containing a genuine error-severity violation is still detected and still exits 1, and the scanned file set matches git diff --cached --name-only.
Summary
In a linked git worktree (
git worktree add),react-doctor --stagedrefuses to scan and exits 1, reporting that ~60 config files differ between the index and the worktree — including git-ignorednode_modules/**/package.jsonmanifests that can never be staged.The trigger is the
GIT_DIRenvironment variable, which git exports to hooks only from a linked worktree, where it points at<main>/.git/worktrees/<name>rather than a real.gitdirectory. Because git exports it for every hook invocation, this makes a--stagedpre-commit hook fail on every commit made from a worktree.This is adjacent to but distinct from #1501 and #1620, both of which are closed — see "Relationship to existing issues" below.
Repro
GIT_DIRis set explicitly here to reproduce outside a hook; inside a realpre-commithook git sets it for you.Expected
Scans the staged files, exactly as it does when
GIT_DIRis unset.Actual
Exit 1, zero findings reported. In a pre-commit hook this surfaces as a false "error-severity findings" failure.
Version boundary (measured, same repo, same index, same command)
GIT_DIRsetSo it is a regression introduced somewhere in 0.8.x.
0.9.11-dev.8606dddwas published ~9 minutes after #1620 was closed, and still reproduces, which is what convinced me this is a separate defect rather than the same one.Layout boundary
A main worktree is unaffected at every version. Verified on git 2.50.1 that git exports
GIT_DIRto hooks only from a linked worktree — from a main worktree it is not exported at all, from either the repo root or a subdirectory. That is why this only bites worktree users.Scope boundary
Only
--stagedis affected.--scope changed --base origin/mainbehaves identically with and withoutGIT_DIR.Relationship to existing issues
GIT_DIRfor nested git commands. That fix is present — the bundle scrubsGIT_DIR: void 0from spawned git children — but the--stageddivergence check evidently resolves the repo before/outside that path, so it is not covered.GIT_DIR, and0.9.11-dev.8606ddd(published after that issue closed) still fails here, while the same build passes withGIT_DIRunset. So the git-ignored-config half may be fixed while the linked-worktree resolution is not.If you consider this a duplicate of either, happy to close — but the
GIT_DIR-set /GIT_DIR-unset asymmetry on a post-fix build seemed worth reporting separately.Workaround
Wrapping the hook invocation with
env -u GIT_DIRrestores correct behaviour, and is a no-op for main-worktree users since git does not export the variable there:I verified the workaround does not weaken the gate: with
GIT_DIRunset in a linked worktree, a staged file containing a genuine error-severity violation is still detected and still exits 1, and the scanned file set matchesgit diff --cached --name-only.