Also available in: Español · Português · Français · العربية
Git Hooks: The Full List, and Which Ones Can Stop You
The complete set git documents, and the measured answer to the only question that matters: can this hook stop the thing you are doing?
What is a git hook?
A git hook is an executable file in your repository's hooks directory, named after a moment in git's life. When that moment arrives — you are about to commit, you have just merged, a push has reached the server — git runs the file. This is how a project enforces a commit message format, runs a linter before code can land, or refuses a force-push to the main branch.
Git documents 28 of them. Most people meet three or four. The rest cover applying patches by mail, rebasing, the receiving end of a push, garbage collection, and a bridge to Perforce, and several run in places you would never guess from the name.
The question anyone actually arrives with is simple: if this hook fails, does it stop me? Every reference we could find answers by copying the list out of git's manual. This page answers it by running them.
How to use it
- Type a hook name. You get where it runs, what git's documentation says about its exit status, and what happened when it was actually installed and told to fail.
- Or search the whole set. The table below holds all 28. Searching a git command — commit, push, git am — brings back every hook that fires during it.
- Read the two columns against each other. They come from different places, so where they line up you can trust the answer, and where the documentation has no word for what happens, the measurement supplies one.
What happened when we ran them
Each hook was installed on its own, in a throwaway repository with a local bare remote alongside it, with a body of nothing but an instruction to fail. Then the operation that hook belongs to was performed, and two things were recorded: the exit code the command returned, and whether the repository state actually moved. Nineteen of the 28 can be driven that way; the rest need a Perforce depot, a mail transport, watchman or the newer push protocol, and are left blank rather than guessed at.
Every case also ran with no hook installed at all, and that control had to succeed and move the state before the measurement counted for anything. That is not ceremony. The first version of this experiment reported that the pre-rebase hook cannot stop a rebase — which is false, and happened because the branch it built had nothing to rebase, so the operation did nothing whether a hook existed or not. The control turned a plausible published falsehood into a loud failure.
Of the nineteen: eleven stopped the operation, seven changed nothing whatsoever, and one did something there is no common word for.
The hook that fails without failing
The post-checkout hook cannot stop a checkout. Git's own documentation says it cannot affect the outcome — other than that the hook's exit status becomes the exit status of the command. Measured, that is exactly what happens: the checkout completes, you are on the new branch, and git returns 1.
So a script written as a checkout followed by a chained command, which is how most deployment scripts and CI steps are written, will stop dead on a repository whose post-checkout hook fails. The checkout worked. The command failed. Those are different facts and only one of them is visible to the shell.
One more exit code is worth knowing. When the reference-transaction hook refuses in its prepared state, git does not return a plain failure — it returns 128, its code for a fatal error. Anything matching on exit codes should expect that rather than 1.
The name is not the rule
Everyone learns it as: hooks beginning with pre- can block, hooks beginning with post- cannot. Half of that is right. Nothing named post- stopped anything, and every hook that changed nothing at all was named post-something.
The other half fails. Only 6 of the 11 hooks that stopped an operation are named pre-something. The other five are applypatch-msg, commit-msg, prepare-commit-msg, update and reference-transaction — so nearly half of what can stop you gives no warning in its name. prepare-commit-msg is the trap inside the trap: it begins with the letters p-r-e, is not a pre- hook, and blocks.
The real rule is whether git consults the exit status at the point the hook runs, which is a property of the operation rather than of the name. It is why update stops a push, why reference-transaction can refuse a branch from being created, and why post-checkout can make a command fail without changing anything.
What this page cannot tell you
It is one git version on one platform. The measurement was taken with the git version printed beside the counts, on Windows, and while hook semantics change slowly they do change. Where the documentation and the measurement agree — which is everywhere they overlap — the answer is as solid as it gets without reading the source.
Nine hooks were not measured, and it says so on their rows rather than filling them in. One of those, pre-auto-gc, was attempted and abandoned: automatic garbage collection only runs once git decides a repository has enough loose objects, and that decision samples a directory rather than counting, so no test repository small enough to build would trigger it. A row whose control cannot be made honest is left out.
Finally, this is about whether a hook can stop an operation, not about whether it should. A hook that rejects work is only useful if the person it stops can tell why, and git prints nothing on your behalf — whatever your hook writes to standard error is the entire error message anyone sees.
Why is it free?
The whole list is a couple of kilobytes shipped with the page and searched in your browser. Nothing you type is uploaded, nothing is logged, and there is no account to make.
No sign-up, no limits, and no watermark on anything you copy out.