Theory
Theory: Hooks are Local Policy; the Server is Real Policy
A hook is an executable Git runs by filename. Exit non-zero aborts the Git operation. Client hooks are not cloned (by design: a clone must not execute a stranger’s scripts). Therefore they are courtesy. Server pre-receive / update and CI are enforcement.
Invariants
.git/hooks/pre-commitruns on this clone only, unlesscore.hooksPathpoints at a shared dir.--no-verifyskips clientpre-commitandcommit-msg.- The web editor on a forge never runs your laptop hooks.
core.hooksPathandinit.templateDirare how a Linux user shares hooks without committing.git.
git commit
→ pre-commit → commit-msg → object exists
git push
→ pre-push (client) → network → pre-receive (server) → CI
Why both
Client hooks fail in milliseconds (whitespace, WIP subject). CI fails in minutes (tests, secret scan) and cannot be skipped with --no-verify. Put the same checks in both; put policy on the server.
What can break
- Forgetting
chmod +x. - Hooks that print to stdout and corrupt
commit-msgfiles. - Assuming teammates have your hooks after
git clone.
How to read this chapter
Types, writing, templates vs CI, lab; then prepare-commit-msg, post-checkout/merge, --no-verify; then config-based hooks (Git 2.54+), which define several named hooks per event in any config file.