Git Hooks
debt(d7/e3/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints note that style errors and linting failures only appear in CI (not locally) and slow feedback loops are the symptom — these issues surface only when someone notices CI failing repeatedly or reviews the repo setup, not through automated static analysis. Tools like captainhook, grumphp, husky, and pre-commit exist to address the gap but their absence is not auto-detected.
Closest to 'simple parameterised fix' (e3). The quick_fix points to adopting a tool like CaptainHook or GrumPHP with hook configuration — a small but non-trivial setup task involving config files and team onboarding. It's more than a one-line patch but contained within the repository's tooling setup rather than spanning multiple application components.
Closest to 'persistent productivity tax' (b5). The common_mistakes show that missing or slow hooks impose a persistent tax: every developer gets a slower feedback loop, team members running without hooks create inconsistency, and undocumented install steps mean new clones silently lack protection. This affects multiple work streams (onboarding, daily commits, CI round-trips) but doesn't reshape the entire codebase architecture.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception is explicit: developers commonly believe git hooks replace CI, but hooks are local-only and trivially bypassed with --no-verify. This directly contradicts the mental model that 'a hook is a gate' — the 'obvious' interpretation of a pre-commit hook is that it enforces policy, when in reality it is purely advisory and skippable.
Also Known As
TL;DR
Explanation
Git hooks live in .git/hooks/ and are not version controlled by default. Types: pre-commit (run before commit, exit 1 to abort), commit-msg (validate message format), pre-push (run before push to remote), post-merge (run after merge — useful for dep updates), pre-rebase. For team-shared hooks, use a tools/hooks/ directory committed to the repo and a setup script that symlinks them, or Husky (Node.js projects), CaptainHook (PHP projects).
Common Misconception
Why It Matters
Common Mistakes
- Slow pre-commit hooks — hooks that take more than 5-10 seconds get bypassed with --no-verify.
- Storing hooks only in .git/hooks/ — not version controlled; new clones don't get them.
- Not documenting how to install hooks in README/Makefile — team members run without them.
- Pre-push hooks that run the entire test suite — too slow; run fast lint checks in pre-commit, reserve tests for CI.
Code Examples
# Hook not shared — only in .git/hooks/ (not version controlled):
# New developer clones repo
# .git/hooks/ is empty — no hooks installed
# They commit without linting, push fails CI on formatting
# CaptainHook for PHP — shared, version controlled:
# composer require --dev captainhook/captainhook
# captainhook.json (committed):
{
"pre-commit": {
"enabled": true,
"actions": [
{"action": "vendor/bin/php-cs-fixer fix --dry-run"},
{"action": "vendor/bin/phpstan analyse --no-progress"}
]
},
"commit-msg": {
"enabled": true,
"actions": [{"action": "\\CaptainHook\\App\\Hook\\Message\\Action\\Regex",
"options": {"regex": "/^(feat|fix|docs|chore|refactor|test)(\\(.+\\))?: .{3,}/"}
}]
}
}
# README: 'Run: vendor/bin/captainhook install'