fix: set GIT_WORK_TREE in pre-commit hook for git worktree compatibility#1207
fix: set GIT_WORK_TREE in pre-commit hook for git worktree compatibility#1207
Conversation
biome check --staged needs GIT_WORK_TREE to resolve staged file paths when running from a subdirectory in a git worktree. Git sets GIT_DIR but not GIT_WORK_TREE when invoking hooks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: CL Kao <clkao@datarecce.io>
Move GIT_WORK_TREE from inline on lint:staged to a top-level export in pre-commit so it covers git diff --cached (the guard condition) and all downstream tools. Add the same export to pre-push for consistency, since vitest and tsc could shell out to git internally. Add tests/test_hooks_worktree.sh to verify biome --staged behavior from js/ with and without GIT_WORK_TREE. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@datarecce.io>
gcko
left a comment
There was a problem hiding this comment.
Review: Adversarial analysis + follow-up fixes
Issues found with the original PR
1. Only fixed part of the problem - pre-push was unaddressed
The pre-push hook has the same worktree exposure. While its git operations are mostly commit-based (git diff SHA..SHA), tools like vitest related and tsc could internally shell out to git. Consistency across hooks prevents future surprises.
2. Inline GIT_WORK_TREE only covered biome, not the guard condition
The original fix set GIT_WORK_TREE inline on line 14 (pnpm lint:staged), but git diff --cached on line 10 - which decides whether to lint at all - ran without it. In a worktree where git environment is incomplete, this guard could silently return empty, skipping lint entirely. Moving to a top-level export covers both.
3. Shifting diagnosis in the Slack thread raised confidence concerns
The root cause bounced between sandbox EPERM, biome .git file handling, monorepo path prefix mismatch, and missing GIT_WORK_TREE. Testing was needed to confirm the actual behavior.
What was done
- Moved GIT_WORK_TREE from inline on pnpm lint:staged to export GIT_WORK_TREE at the top of pre-commit (covers all git operations in the script)
- Added the same export to pre-push for consistency
- Verified commit-msg needs no changes (only reads a file path, no git worktree interaction)
- Added tests/test_hooks_worktree.sh for manual verification
Testing
Ran tests/test_hooks_worktree.sh - all 4 tests pass:
| Test | Result |
|---|---|
| biome check --staged finds staged files from js/ (no GIT_WORK_TREE) | PASS |
| biome check --staged finds staged files from js/ (with GIT_WORK_TREE) | PASS |
| git diff --cached returns repo-root-relative paths | PASS |
| git rev-parse --show-toplevel resolves correctly | PASS |
This confirms:
- biome --staged works correctly from js/ in normal repos (the Slack reply 30 "always been broken" theory was wrong)
- Setting GIT_WORK_TREE redundantly in a non-worktree repo is harmless
- The export approach is safe for both worktree and non-worktree usage
Codecov Report✅ All modified and coverable lines are covered by tests. 🚀 New features to boost your workflow:
|
Summary
biome check --stagedfails silently (0 files checked) when running in a git worktree because git setsGIT_DIRbut notGIT_WORK_TREEwhen invoking hooksjs/subdirectoryGIT_WORK_TREE="$REPO_ROOT"to the pnpm lint commandTest plan
git commitwith staged JS/TS files works in a git worktreegit commitstill works in the main repo (non-worktree)biome check --stagedfinds and checks the correct files🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com
Signed-off-by: CL Kao clkao@datarecce.io