Skip to content

Commit b82b293

Browse files
LTSCommerceclaude
andcommitted
fix(hooks): unset git env vars in pre-commit vendor check for worktree support
When running from a git worktree, git exports GIT_DIR, GIT_WORK_TREE, and GIT_INDEX_FILE into the hook environment. These variables caused git commands inside vendor sub-repos to use the parent project's metadata instead of the vendor's own .git directory, producing thousands of spurious "deleted" entries and blocking commits. The fix unsets these three variables before the vendor-scanning loop. By that point PROJECT_ROOT and COMPOSER_COMMITS are already captured, so the unset is safe. Each vendor sub-repo then discovers its own .git directory naturally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ea2286b commit b82b293

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Plan: Fix pre-commit hook for git worktree support
2+
3+
## Problem
4+
5+
The `pre-commit-check-vendor-uncommitted` hook fails in git worktrees. When a
6+
commit is made from a worktree, git exports `GIT_DIR` (and potentially
7+
`GIT_WORK_TREE`, `GIT_INDEX_FILE`) into the hook's environment. These variables
8+
point to the worktree's git metadata, not to vendor sub-repos.
9+
10+
When the hook `cd`s into a vendor directory and runs `git status --porcelain`,
11+
git ignores the vendor's own `.git` directory and instead uses the inherited
12+
`GIT_DIR`. This causes git to compare the vendor directory against the
13+
*parent project's* index, producing thousands of spurious "deleted" entries
14+
and blocking the commit.
15+
16+
### Reproduction
17+
18+
```bash
19+
# From a worktree:
20+
export GIT_DIR="/workspace/.git/worktrees/worktree-child-00024-contact-sections"
21+
cd /workspace/vendor/lts/php-qa-ci
22+
git status --porcelain | wc -l
23+
# => 2984 (all wrong — the vendor repo is actually clean)
24+
25+
# After unsetting:
26+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
27+
git status --porcelain | wc -l
28+
# => 0 (correct)
29+
```
30+
31+
## Fix
32+
33+
In `git-hooks/pre-commit-check-vendor-uncommitted`, unset `GIT_DIR`,
34+
`GIT_WORK_TREE`, and `GIT_INDEX_FILE` before entering the vendor-scanning loop.
35+
These variables are only meaningful for the *parent* repository's commit
36+
operation; vendor sub-repos must discover their own `.git` directory naturally.
37+
38+
The `PROJECT_ROOT` is captured from `git rev-parse --show-toplevel` *before*
39+
the unset, so it correctly resolves even in worktree context. The `composer.lock`
40+
parsing also happens before the unset and doesn't use git at all.
41+
42+
### Variables to unset
43+
44+
| Variable | Why it breaks vendor checks |
45+
| ---------------- | ------------------------------------------------------ |
46+
| `GIT_DIR` | Forces git to use parent's git dir instead of vendor's |
47+
| `GIT_WORK_TREE` | Overrides the working tree, misaligning status checks |
48+
| `GIT_INDEX_FILE` | Points to parent's index, not vendor's |
49+
50+
### Placement
51+
52+
Unset immediately before the `while` loop that iterates vendor `.git`
53+
directories (line 77). This is after `PROJECT_ROOT` and `COMPOSER_COMMITS`
54+
are already captured, so those values are unaffected.
55+
56+
## Success criteria
57+
58+
1. Hook passes in a normal (non-worktree) repo with clean vendors
59+
2. Hook passes in a worktree context with clean vendors
60+
3. Hook still correctly detects real uncommitted changes in vendor repos
61+
4. Hook still correctly detects composer.lock out-of-sync conditions
62+
5. `PROJECT_ROOT` resolution is unaffected (captured before unset)

git-hooks/pre-commit-check-vendor-uncommitted

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ if [[ -f "$PROJECT_ROOT/composer.lock" ]]; then
7373
' "$PROJECT_ROOT/composer.lock" 2>/dev/null)
7474
fi
7575

76+
# Unset git environment variables before scanning vendor sub-repos.
77+
# When this hook runs from a git worktree, git exports GIT_DIR,
78+
# GIT_WORK_TREE, and GIT_INDEX_FILE pointing to the worktree's metadata.
79+
# If these leak into vendor sub-repo git commands, git ignores the vendor's
80+
# own .git directory and reports thousands of spurious changes against the
81+
# parent project's index. Unsetting them lets each vendor repo discover its
82+
# own .git naturally. PROJECT_ROOT and COMPOSER_COMMITS are already captured
83+
# above, so this is safe.
84+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
85+
7686
# Find all vendor/*/* directories that contain .git directories
7787
while IFS= read -r -d '' git_dir; do
7888
# Get the repo directory (parent of .git)

0 commit comments

Comments
 (0)