Git Hooks & Automation
Catching problems before they're ever committed or pushed, without anyone having to remember to run a check by hand.
Beginner → Advanced
.git/, which is not tracked by git
itself — cloning a repo does not bring its collaborators' hooks along. That single fact
is why "sharing hooks across a team" is its own problem, covered further down.
| Hook | Runs | Common use |
|---|---|---|
| pre-commit | before a commit message is even opened | lint/format the staged diff, block debug prints |
| commit-msg | after the message is written, before the commit is created | enforce a message format (e.g. conventional commits) |
| pre-push | before anything is sent to a remote | run the test suite, block pushes to protected branches |
| post-checkout | after switching branches | reinstall dependencies if the lockfile changed |
.git/hooks/pre-commit and make it executable. It blocks a
commit if any staged Python file still has a debugger breakpoint in it.
#!/bin/sh
if git diff --cached --name-only | grep '\.py$' | xargs grep -l 'breakpoint()' 2>/dev/null; then
echo "Commit blocked: breakpoint() found in a staged file."
exit 1
fi
.git/hooks/ isn't tracked, the standard fix is to keep your real
hook scripts in a normal, version-controlled folder and point git at it instead.
.pre-commit-config.yaml) and
husky (JS-ecosystem, installs itself via
npm) both automate the core.hooksPath step and manage a list of
checks for you.
pre-receive and post-receive run on whatever machine hosts
the remote, not on a contributor's laptop — they can reject a push outright before it's
accepted. Self-hosted git servers use these directly; on GitHub, this exact job is done
instead by branch protection rules and required status
checks (see the GitHub cheat sheet's branch protection section), since you
don't have direct access to GitHub's server-side hooks.