Skip to content

fix(cli): install git hooks from the repository root only - #861

Merged
blafourcade merged 1 commit into
nextfrom
fix/hooks-install-from-the-root-only
Sep 11, 2026
Merged

fix(cli): install git hooks from the repository root only#861
blafourcade merged 1 commit into
nextfrom
fix/hooks-install-from-the-root-only

Conversation

@blafourcade

Copy link
Copy Markdown
Contributor

🎯 What & why

A stray cli/lefthook.yml holding lefthook's example config kept appearing untracked in linked worktrees (#860). Worse, whatever wrote it also reinstalled the git hooks that every worktree shares.

🛠️ How it works

The chain, reproduced in throwaway repos with lefthook 2.1.12 and pnpm 12.3.4:

  1. In a linked worktree, git exports GIT_DIR into every hook; the main checkout gets only GIT_INDEX_FILE.
  2. A pre-commit or pre-push job runs pnpm inside cli/ (cd cli && pnpm lint, pnpm test:arch, pnpm typecheck, pnpm --dir cli knip, pnpm --dir cli test). When cli/node_modules is missing or stale, pnpm 12 installs first and runs cli/package.json's "prepare": "lefthook install".
  3. With GIT_DIR set and no GIT_WORK_TREE, git takes cli/ for the work tree root. lefthook finds no config there, writes its example, and installs hooks into the shared hooks directory.

The fix:

  • cli/package.json drops prepare and its lefthook devDependency. The root package's prepare already installs the hooks, and the Makefile does too, from the root. Nothing else in cli used lefthook: knip flagged the dependency once the script was gone. The lockfile loses the lefthook entries.
  • cli/tests/architecture/hooks-install-from-the-root.arch.test.ts asserts that no script of this package calls lefthook. It lives in architecture because that project runs in pre-commit on any cli/** change, so it catches the exact edit that would bring the bug back.

🧪 How to verify

  • Red first: the test failed on the old package.json (prepare: lefthook install); green after.
  • In the repro: cd cli && GIT_DIR=<root>/.git lefthook install gives Added config: .../cli/lefthook.yml. Without GIT_DIR there is no file. The pre-commit job cd cli && pnpm lint in a linked worktree creates it. With cli's prepare removed, it does not.
  • Architecture 25 files, 131 tests; typecheck, lint and knip green. This commit and push, made from a linked worktree, left no cli/lefthook.yml.

⚠️ Heads-up

  • Someone who runs pnpm install only inside cli/ no longer gets hooks installed; scripts/doctor.sh already warns when they are missing. Installing from the root is the supported path.
  • || true would not have helped: the file still appears with it. A .gitignore entry would only hide it while the shared hooks keep being reinstalled.
  • cli/package.json is a harness file, so CI runs every mutation scope.

🔗 Linked issue

Closes #860

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb

In a linked worktree git exports GIT_DIR into every hook. A pre-commit or
pre-push job that runs pnpm inside cli/ (`cd cli && pnpm lint`, `pnpm --dir
cli test`, ...) lets pnpm 12 install missing dependencies first, which ran
cli's `"prepare": "lefthook install"`. With GIT_DIR set and no GIT_WORK_TREE,
git took cli/ for the work tree root: lefthook found no config there, wrote
its example into cli/lefthook.yml and reinstalled the hooks every worktree
shares. Reproduced in throwaway repos with lefthook 2.1.12 and pnpm 12.3.4.

The root package's `prepare` already installs the hooks, so cli drops its own
along with its lefthook devDependency, which nothing else used (knip flagged
it once the script was gone). An architecture test asserts that no script of
this package calls lefthook; it failed on the old package.json.

Fixes #860

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60
@blafourcade
blafourcade requested a review from a team as a code owner September 11, 2026 08:35
@blafourcade
blafourcade merged commit 126e88d into next Sep 11, 2026
37 checks passed
@blafourcade
blafourcade deleted the fix/hooks-install-from-the-root-only branch September 11, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant