5 Simple Git Hooks to Manage Your Repository

5 Git Hooks 00 Featured Image

Git is a brilliant tool. It allows you to not only track your changes in a file through hooks but also seamlessly collaborate with other people. In that regard, Git is one tool that pushed the development of FOSS forward.

However, one of the biggest issues with Git is that it takes time and effort to manage your repositories. For example, committing and synchronizing these repositories can take two to three git commands. This makes managing them not only tedious but also prone to user error. Here we show you a few simple, yet effective Git hooks to better manage your repositories.

Note: yYou can also manage Git in Emacs. Learn how!

What Are Git Hooks?

At its core, git-hook is a flexible subcommand that you can use to create custom scripts that run whenever Git performs an action on a repository. For example, it is possible to use hook to automatically check your repository for style errors before you even commit with it.

5 Git Hooks 02 Example Linter
Image source: jslint

The hook subcommand works by reading the “hooks” folder under your repository’s “.git” directory. This folder contains a number of pre-made files that provide a sample script for every action in Git that you can automate.

5 Git Hooks 03 Default Hooks Directory

For the most part, you can write a git hook in any scripting language you wish. This makes it incredibly flexible and approachable for any software developer.

Tip: to get started with Git, you will need to set up Git’s username and email first. Find out how in this guide.

1. Prevent Pushing to Master

One of the most common mistakes that a user makes in Git is to push a commit from a development branch directly to master. This can be incredibly frustrating if you are using Github to track and maintain your projects.

5 Git Hooks 04 Example Git Push

You can prevent this issue by creating a “pre-push” Git hook that will check and confirm whenever you try to push a repository from the master branch.

  1. Go to the Git repository that you want to protect.
5 Git Hooks 05 Cd To Repository
  1. Create a Git hook file with your checking script. Since this is a hook that should run before a “push,” you need to create a “pre-push” hook file:
touch .git/hooks/pre-push
  1. Open your new hook file in a text editor.
nano .git/hooks/pre-push
  1. Inside, write your new “pre-push” hook. For example, the following is a script that will ask for your confirmation when you are pushing from the master branch:
#!/bin/sh
 
protect='master'
current=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
 
if [ $protect = $current ]
then
    read -p "Confirm push to master? Y/n." -n 1 -r < /dev/tty
    echo
    if echo $REPLY | grep -E '^[Yy]$' > /dev/null
    then
        exit 0
    fi
    exit 1
else
    exit 0
fi
  1. Save your new hook. In nano, do this by pressing Ctrl + O, then Ctrl + X.
5 Git Hooks 07 Pre Push Hook Filled
  1. Run the following command to make sure that Git can run your new hook.
chmod +x .git/hooks/pre-push

2. Reject Pushes to the Master Branch

Aside from preventing yourself from pushing to the master, you can also create a server-side hook that will reject any pushes to its master branch. This is incredibly useful if you are sharing a repository with multiple developers.

5 Git Hooks 08 Git Log Sample

Fix this by creating a “pre-receive” hook that will automatically prevent any restricted user from pushing to the master branch.

  1. Create the “pre-receive” Git hook file in your remote repository.
touch .git/hooks/pre-receive
  1. Open this file.
nano .git/hooks/pre-receive
  1. Add the rejection script in your “pre-receive” hook. For example, the following lines of code should work out of the box:
#!/bin/sh
 
branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
 
blacklist=(alice bob)
 
if [[ ${blacklist[*]} =~ $USER ]]; then
    if [ "$branch" == "master" ]; then
        echo "You are not allowed commit changes in this branch"
        exit 1
    fi
fi
  1. Save your new hook file. In my case, I need to press Ctrl + O, then Ctrl + X to save the file.
  1. Save your hook script and make it executable.
chmod +x .git/hooks/pre-receive

Tip: you can also use Git alias to make Git usage more efficient.

3. Lock the Repository from Rebasing

Another common mistake that a user makes in Git is rebasing the currently active branch. This can be a frustrating issue if you are working on a repository with multiple contributors, as rebasing will remove the commits that other users have made.

5 Git Hooks 11 Git Rebase Man Page

You can prevent this issue by creating a “pre-rebase” hook that will check whether the current branch is locked.

  1. Create a “pre-rebase” file in your “.git/hooks” directory:
touch .git/hooks/pre-rebase
  1. Open this file for edit.
nano .git/hooks/pre-rebase
  1. Add the rebase script inside your new hook file.
#!/bin/sh
 
branch="$2"
[ -n "$branch" ] || branch=$(git rev-parse --abbrev-ref HEAD)
lock="branch.${branch}.rebaselock"
 
if [ "$(git config --bool "$lock")" = true ]; then
echo "pre-rebase hook: \"$lock\" is set to true. Refusing to rebase."
exit 1
fi
  1. Save your new hook file and make it executable.
chmod +x .git/hooks/pre-rebase

4. Force a Style and Syntax Check on Your Code

One of the most helpful uses of a Git hook is by linking it with a code linter. This is a simple program that checks whether your code follows the style and format for a project.

5 Git Hooks 14 Shellcheck Man Page
  1. To link a linter to your Git repository, first make a “pre-commit” hook file.
touch .git/hooks/pre-commit
  1. Install the appropriate linter for the language of your project. In this case, I am using “shellcheck” to analyze my Bash code:
sudo apt install shellcheck
  1. Open your new hook file and add the following script.
#!/bin/bash
for file in $(git diff --cached --name-only --diff-filter=AM | grep -E '\.sh$')
do
 
  shellcheck "$file" # Run the linter for every new file.
 
  if [ $? -ne 0 ]; then
    exit 1 # Terminate the commit if the linter fails.
  fi
done
  1. Save your new hook file and make it executable:
chmod +x .git/hooks/pre-commit

5. Automatically Notify Users with Repository Changes

Lastly, you can also create a Git hook that will automatically send an e-mail whenever your repository receives a new commit. This is helpful if you want to create a simple notification system for your repository.

  1. Create a “post-receive” hook file in your repository’s .git/hooks directory:
touch .git/hooks/post-receive
  1. Open your new Git hook file and enter the following script:
#!/bin/sh
 
commit_message=$(git log -1 --pretty=%B)
users=("alice@example.invalid" "bob@example.invalid" "mary@example.invalid")
 
for user in "${users[@]}"; do
    mail -s "New Commit: $commit_message" $user < /dev/null
    done
  1. Save your new hook file and make it executable.
chmod +x .git/hooks/post-receive

Frequently Asked Questions

Can I write my Git hooks in a compiled language, such as C?

One of the biggest limitations of Git hooks is that it requires you to use a language that you can run directly from the terminal. This means that Git hooks does not support any compiled language for its scripts. For example, you can create a new Git hook using either Python or Shell but not C or C++.

Is it possible to run multiple hooks in the same Git repository?

Yes. While the examples above show hooks as single, discrete features, you can easily mix them together to create your own unique workflow, making Git hooks incredibly flexible and adaptable for any coding situation. For example, you can use both the “Prevent Push to Master” pre-push hook and the “Syntax Check” pre-commit hook in your own repository.

Why are the e-mail Git hooks not sending an e-mail to users?

This issue is most likely due to your remote server not being able to properly send any outgoing e-mails. To fix this, make sure your remote server is secure and that it has a working mail delivery agent along with an SMTP domain.

Image credit: Unsplash. All alterations and screenshots Ramces Red.

Is this post useful?
Subscribe to our newsletter!

Our latest tutorials delivered straight to your inbox

Ramces Red
Ramces Red - Staff Writer

Ramces is a technology writer that lived with computers all his life. A prolific reader and a student of Anthropology, he is an eccentric character that writes articles about Linux and anything *nix.