Beginner's Guide to Git Hooks: Examples and Practical Uses
Git hooks are scripts that run automatically in response to specific events in a Git workflow. They can be useful for enforcing project standards, automating processes, or performing checks before or after actions like committing or pushing changes.
Here’s a simple tutorial on how to use Git hooks, including a walkthrough example to practice as you learn.
Navigate to your Git repository: Open your terminal and navigate to the root directory of your Git project.
cd /path/to/your/repository
Locate the .git/hooks
directory:
Inside your repository, there is a hidden .git/hooks
directory where all hook scripts are stored.
Choose a hook to modify:
There are many hooks available, but we’ll start with the pre-commit
hook, which runs before a commit is created. To see the available hooks, list the contents of the .git/hooks
directory:
ls .git/hooks
You’ll see files like pre-commit.sample
, commit-msg.sample
, etc. These are sample hooks.
Create or modify a hook:
Rename or create the script you want to use (e.g., pre-commit
), and make sure it is executable.
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Let’s create a simple pre-commit
hook that checks for trailing spaces in the files being committed. This will help you practice using Git hooks.
Edit the pre-commit
file:
Open the pre-commit
file with your favorite text editor.
nano .git/hooks/pre-commit
Add the script: Add the following code to check for trailing spaces and prevent committing files with trailing spaces.
#!/bin/sh
# Check for trailing spaces in staged files
# Get the list of staged files
files=$(git diff --cached --name-only --diff-filter=AM)
# Loop through each file
for file in $files; do
# Check if the file has trailing spaces
if grep -q '[[:blank:]]$' "$file"; then
echo "Error: Trailing spaces found in $file"
exit 1
fi
done
# Allow commit if no issues found
exit 0
Save and exit:
After you’ve added the script, save the file and exit your editor. For nano, you can press CTRL + X
, then press Y
to confirm and Enter
to save.
Make some changes: Modify one of the files in your repository and add a trailing space.
For example:
echo "This is a test file. " > test.txt
Stage the file: Add the file to the staging area.
git add test.txt
Try to commit:
When you try to commit the file, the pre-commit
hook will run, checking for trailing spaces.
git commit -m "Test commit"
Since there’s a trailing space in test.txt
, the commit will be blocked, and you will see an error like:
Error: Trailing spaces found in test.txt
Fix the issue:
Remove the trailing space from test.txt
:
sed -i 's/[[:blank:]]*$//' test.txt
Commit again: Now that the trailing spaces are removed, stage and commit the changes again.
git add test.txt
git commit -m "Test commit"
This time, the commit should succeed, as there are no trailing spaces.
You can experiment with other Git hooks as well:
commit-msg
: Run before a commit message is finalized. You can use it to enforce a specific format for commit messages.post-commit
: Run after a commit is made. This is useful for logging or triggering other actions after a commit.pre-push
: Run before changes are pushed to a remote repository. You could use it to ensure your branch is up to date before pushing.You can explore more Git hook scripts in the .git/hooks
directory and modify them as needed.
If you want to share your hooks with a team, Git doesn’t track the .git/hooks
directory. However, you can store the hooks in a versioned directory and use a script to copy them into the .git/hooks
directory.
For example, create a hooks
directory in your project’s root:
mkdir hooks
Then copy your hook script into this directory and create a setup script to install them:
cp .git/hooks/pre-commit hooks/pre-commit
Create a script to set them up:
#!/bin/bash
cp hooks/* .git/hooks/
chmod +x .git/hooks/*
Now, team members can run this setup script to install the hooks.
This simple tutorial has introduced you to using Git hooks. You can modify these hooks for your own use cases, such as enforcing coding standards or automating tasks during your development workflow.
Here's a short summary of the default Git hooks that come with a fresh git init
:
applypatch-msg
Runs after applying a patch with git am
, allowing you to inspect or modify the commit message.
pre-applypatch
Runs before applying a patch with git am
. Typically used to check the patch or pause the process.
pre-commit
Runs before a commit is finalized. Commonly used for checks like code linting, running tests, or validating files.
prepare-commit-msg
Runs after the commit message file is created but before it’s finalized. Useful for modifying the commit message template (e.g., adding issue references).
commit-msg
Runs after the commit message is prepared. Can be used to enforce rules for commit message formatting.
post-commit
Runs after a commit is completed. Useful for notifications or other tasks that occur post-commit.
pre-merge-commit
Runs before a merge commit is created, allowing you to perform checks specific to merges.
pre-rebase
Runs before a rebase starts. Often used to prevent rebasing certain branches.
pre-push
Runs before pushing changes to a remote repository. Useful for running tests or ensuring branch policies are met.
fsmonitor-watchman
Integrates with Watchman to improve Git performance by monitoring file changes. (Specific to systems with Watchman installed.)
pre-receive
Runs before changes are accepted by a remote repository. Commonly used to enforce access controls or validate pushes.
update
Runs once per branch before accepting changes, allowing you to enforce specific branch policies.
post-update
Runs after changes are accepted by a remote repository. Often used to trigger actions like updating deployment systems or notifying services.
push-to-checkout
Runs when git push
is used to deploy changes to a repository’s working directory.
post-rewrite
Runs after commands that rewrite commits (like git commit --amend
or git rebase
). Used to log or handle rewritten commits.
The hooks ending with .sample
are disabled by default (acting as templates). You can enable them by renaming them (e.g., remove the .sample
extension) and adding executable permissions.