Hooks
Last updated on 2026-07-15 | Edit this page
Overview
Questions
- How do I automate checks on my commit?
- How do I check changes before a commit?
Objectives
- Learn about using hooks to improve quality of commits
Git hooks are scripts that get run when a specific event occurs in git. The scripts can be written in any language and do anything you like, so any executable script can be a hook.
Git hooks can trigger events on the server side or locally, and
commonly used hooks include: - pre-commit: Executed before
the git commit command and is usually used to check the
changes with linters or tests. - prepare-commit-msg:
Executed before after the commit message is created, but before the
commit message editor is started. Good for changing the default commit
message programmatically before the user sees it. -
commit-msg: Validates the commit message, can be used to
check whether the commit message adheres to project policies -
post-commit: Runs after the commit, often used for
notifications or logging. - pre-receive: Server-side hook,
which runs before a push is accepted, commonly used to enforce project
policies
Examples of local events that can trigger hooks include
commit (pre- or post-commit hooks), checkout
or rebase. Pre-commit hooks are perhaps the most common and
useful ones: they trigger actions before the code is committed and if
the hook script fails, then the command is aborted. This can be very
powerful - you can automatically run linters, before the code is even
committed.
List of pre-written pre-commit hooks: https://github.com/pre-commit/pre-commit-hooks
The executable files are stored in the .git/hooks/
directory in your project directory. A pre-commit hooks will be an
executable file in this directory stored with the magic name
pre-commit. Check the directory, there are already several
examples.
Before creating the hook, make sure flake8 is installed
in your environment:
Now, let’s create the hook:
And add the following text to it:
#!/usr/bin/env bash
set -eo pipefail
flake8 hello.py
echo "flake8 passed!"
Now let’s make hello.py:
Make the hook file executable, otherwise Git will silently ignore it:
And add some text to it:
The typo is on purpose. Add and commit it to the repository.
Challenge 1: Enforcing commit message format with a hook
Create a file called commit-msg within the directory
.git/hooks/. It must be able to determine if the commit
message is prefixed by feat:, fix:, or
docs:; otherwise, it will prevent the commit from being
made and provide feedback. Run chmod on the file to make it
executable. To test, initially do an attempt at committing using an
invalid message like “updated stuff” and see that it will fail. Then
commit again using a valid commit message such as “feat: add new recipe”
and verify that it succeeds.
The commit-msg hook receives the path to a temporary
file containing the commit message as its first argument. Inside the
script, you can access it with $1. To read the contents of
that file: cat "$1"
You can use grep with regex to check the message format.
For example:
-q runs grep quietly (no output), -E
enables extended regex, and ^(feat|fix|docs): matches lines
that start with one of these three words followed by a colon.
In a hook script, if a command exits with a non-zero status, the
commit is aborted. So exit 1 rejects the commit.
GitHub actions are the equivalent of server-side hooks on GitHub.
There are lots of things that can be done with GitHub actions: https://docs.github.com/en/actions
Here is an example of a simple cron job: https://github.com/mpi-astronomy/XarXiv

Materials: https://verdantfox.com/blog/how-to-use-git-pre-commit-hooks-the-hard-way-and-the-easy-way
- Git provides a list of different hooks for you to run tasks at specific times in the commit
- Use the
pre-commithook to check for change conformity before changes are committed