Theory

Updated

October 30, 2026

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

  1. .git/hooks/pre-commit runs on this clone only, unless core.hooksPath points at a shared dir.
  2. --no-verify skips client pre-commit and commit-msg.
  3. The web editor on a forge never runs your laptop hooks.
  4. core.hooksPath and init.templateDir are 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-msg files.
  • 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.