Hooks catch lint errors, bad messages and failing tests before they leave your machine.
Hooks are executable scripts Git runs at certain events. They live in .git/hooks/ (which ships .sample files to copy) or in a directory set with core.hooksPath. A hook is any executable named after the event, in any language with a shebang line.
Common client-side hooks:
pre-commit: before the commit message is asked for. Exit non-zero to abort, which is ideal for linters and formatters.prepare-commit-msg/commit-msg: edit or validate the message, for example to enforce Conventional Commits or an issue ID.commit-msgreceives the message file path as$1.pre-push: before anything is sent; run the faster test suite here.post-checkout/post-merge: after switching or pulling, for example to reinstall dependencies when a lockfile changed.
Servers have their own hooks (pre-receive, update, post-receive), which hosting platforms expose as protected branches, required checks and webhooks.
Two facts shape how hooks are used in teams:
- Hooks are not cloned.
.git/hooksisn't versioned, so to share them commit a folder such as.githooks/and have everyone rungit config core.hooksPath .githooks, or use a manager like pre-commit, Husky or Lefthook that installs them. - Hooks are bypassable.
git commit --no-verify(-n) skipspre-commitandcommit-msg;git push --no-verifyskipspre-push. So hooks are a convenience for fast feedback, and CI remains the real gate.
Keep hooks fast, a couple of seconds at most, and check only staged files, or people will start using --no-verify by habit.
Example
mkdir -p .githooks
cat > .githooks/commit-msg <<'END'
#!/bin/sh
# Require "ABC-123: summary" style messages
if ! head -1 "$1" | grep -qE '^[A-Z]+-[0-9]+: .+'; then
echo "commit-msg: start the message with a ticket ID, e.g. 'ABC-12: Fix login'" >&2
exit 1
fi
END
chmod +x .githooks/commit-msg
git config core.hooksPath .githooks
git add .githooks && git commit -m "ABC-7: Add commit-msg hook"
git commit -m "oops" # rejected by the hookRemember
- A hook is an executable named after the event in .git/hooks or core.hooksPath
- Non-zero exit from pre-commit, commit-msg or pre-push aborts the action
- Hooks aren't cloned; share via core.hooksPath or a hook manager
- --no-verify bypasses them, so CI must still enforce rules
Watch out for
- Forgetting chmod +x on the hook file — Git silently ignores non-executable hooks.