Repository navigation
fix(hooks): clear inherited GIT_DIR before the pre-push test run - #1021
vernonstinebaker wants to merge 2 commits into
Conversation
`git push` from a worktree exports GIT_DIR and GIT_PREFIX; a push from a normal clone exports neither (verified in nullclaw#1020 with a hook that dumps its environment). The suite inherits it, so every test that spawns `git` against a fixture repository of its own instead operates on this repository — 10 failures (skills.installSkillFromGit x7, workspace_audit staged-diff, and 2 more), all spurious. That makes the gate unusable in a worktree, which is this repo's documented workflow: the only options were --no-verify or pushing from the root checkout, and both defeat the point of the hook. Unset the inherited git state before running the suite so it behaves the same however the push was launched. Verified by running this hook with GIT_DIR set (the condition that previously produced 7380/7400 with 10 failed): now 7387/7396, exit 0. The deeper fix is for the git-spawning tests to sanitize their child environment themselves; that is tracked separately in nullclaw#1020. Fixes nullclaw#1020
Extends the same hook that clears GIT_DIR (nullclaw#1020) so it also refuses to let a push through when the test run left untracked files behind. The suite can drop fixtures into the working tree. They are harmless where they sit, but the next `git add -A` commits them silently. That is how nullclaw#1012 and nullclaw#1019 each ended up carrying workspace-audit and skills test fixtures -- `config.txt`, `history.env`, `SKILL.md`, `skill.json`, `assets/payload.txt`, and fixture directories under `skills/` -- along with a one-line `# Not a skill` stub that had replaced the 974-line README. Both branches were single squashed commits, which is the shape that captures whatever happens to be lying around in the tree. Deliberately limited to untracked ("??") entries. Modified tracked files are nearly always work in progress, and blocking on those would make the hook hostile to normal development; the residue problem is specifically about files appearing from nowhere and being swept up by an add-everything commit. The check depends on the `unset` above it: with GIT_DIR still exported from a worktree push, `git status` reports on the wrong repository. Verified by running the hook directly: clean tree passes, an untracked file fails with the offending paths listed, and a modified tracked file still passes.
|
Update with a reproduction and a verification, since the scope of this PR turns out to be larger than the original 7-line fix suggested. This is not only a spurious-test-failure bug — it corrupts branchesThe original description says inherited Reproduced on a fresh worktree at That last commit adds This is exactly the residue in #1012 and #1019Both those PRs arrived carrying The chain:
Both affected branches are single squashed commits — the shape that sweeps up whatever is lying around. Verification of the fixSame worktree, same inherited
So the Scope of this PR, restatedI previously framed the untracked-file check as the fix for the residue. That was wrong — it is a safety net, and it addresses the residue only indirectly. The residue itself is a symptom of this PR's original bug, so this PR is closer to a data-integrity fix than a developer-ergonomics one, and is the highest-value open item on my side for that reason. For the record, this also corrects an earlier note of mine: I had described the residue as a second, unrelated leak and pointed at #1038. #1038 is unrelated — it touches only |
Fixes #1020.
The problem
.githooks/pre-pushcannot pass from a worktree, which is this repo's documented workflow (docs/nullclaw-maintainer-worktree-workflow.md).git pushfrom a worktree exportsGIT_DIR(andGIT_PREFIX); from a normal clone it exports neither. The suite inherits it, so every test that spawnsgitagainst a fixture repository of its own instead operates on this repository — 10 spurious failures:Because it fails loudly but wrongly, the only options were
--no-verifyor pushing from the root checkout — both defeat the point of the gate.Reproduced deterministically
GIT_DIRGIT_DIR=<worktree gitdir>And with a throwaway bare repo + a hook dumping
env | grep ^GIT:(no GIT_* exported)GIT_DIR=/…/.git/worktrees/wt,GIT_PREFIX=Git must export
GIT_DIRfrom a worktree because.gitis a file there, which is why this never reproduces outside one.The fix
Clear the inherited git environment before running the suite:
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR GIT_PREFIXValidation
GIT_DIRset (the exact failing condition): 7387/7396, exit 0 — previously 7380/7400 with 10 failed.--no-verify, and the fixed hook ran live under a realgit pushfrom a worktree —Running tests...→7387/7396 (9 skipped)→ push succeeded.zig fmt --check src/clean; docs-only + hook, no source changes.The deeper fix — having the git-spawning tests sanitize their own child environment — is tracked in #1020 as a follow-up, so the tests are correct regardless of how the suite is launched.