Custom git hooks — Automate your development workflow

Ashaba John
The Andela Way
Published in
4 min readNov 7, 2017

Version control has become a central requirement for modern software development. Like many other Version Control Systems, Git has a way of firing off custom scripts that perform certain operations. These scripts are referred to as hooks. There are two groups of hooks: client side and server side. Client-side hooks perform client operations such as committing and merging, while Server-side hooks perform Git server operations such as receiving pushed commits.

What is covered in this article

In this article, we are going to create our custom scripts to ensure that:

  1. The staged codebase doesn’t contain certain strings e.g. pdb usage in python files or console.log in javascript(pre-commit).
  2. The commit message is properly formatted and is conformant to a desired pattern(commit-msg).
  3. You don’t rebase any commits that have already been pushed(pre-rebase).

Note: You can use any scripting languages of your choice to create hooks and here we are going cover the following topic inruby and shell

Prerequisites

Before we start, ensure that you have git installed on your system.
Secondly, you should be familiar with git basic usage. If you need a head start, here is a good place to start.

Create sample project on github and clone it locally. You’ll need it for a smooth read-work-along.

Getting started

The hooks are all stored in the hooks subdirectory of the Git directory that’s .git/hooks. If you list files in this directory, you will notice there are various hooks. You can implement any of them by removing the .sample extension.

Open your terminal or powershell for windows;
Navigate to $ cd /path-to-your-git-repo/.git/hooks

Creating a Pre-commit hook

Create your custom pre-commit hook

$ touch pre-commit

Copy contents of the sample pre-commit to the custom pre-commit

$ cp pre-commit.sample pre-commit

Make the pre-commit script executable

$ chmod +x pre-commit

Open the pre-commit script and start the real scripting with your text editor

$ open -e pre-commit # mac os x
$ gedit pre-commit # linux

Edit the sample script to meet our expectations

Add the following line of code to ensure that there are no whitespaces at the end of a file

# If there are whitespace errors, print the offending file names and fail.git diff-index --check --cached $against --

Next we grep the staged files with .py extensions and check for the existence of pdb usage and print statements. Existence of these strings results in exit 1 thus aborting the commit

That’s it for the pre-commit hooks. Save the file and exit the editor.

Save the changes. At this point you can test by adding print statements or import pdb to a python script.Stage the files changed and try committing them, the hook fires the following message and aborts committing.

changedfile.py:2:import pdb
Error commiting changes: Please remove pdb and its usage

Bravo!! You realize that the commit will be aborted with relevant error messages.

Creating a commit-msg hook

The commit-msg hook takes one parameter, which again is the path to a temporary file that contains the current commit message. If this script exits non-zero, Git aborts the commit process, so you can use it to validate your project state or commit message before allowing a commit to go through. In this section of this chapter, I’ll demonstrate using this hook to check that your commit message conforms to a required pattern.

In the /path-to-your-git-repo/.git/hooks directory of your sample project, create a new file named commit-msg and make it executable as in the above.

We shall be using ruby in this section to check for commit message and validate it to suite our standards. Note that you can define your own standards of a commit message for the team to adhere to.

In the above script, we use regular expressions to check and validate the format of a message to be like chore(module): message of the commit

Short of this format will result in the commit being aborted:

$ git commit -am 'test'
[POLICY] Your message is not formatted correctly
[STANDARD] Your message should be in the format: ‘feat(module): commit message’
$ git commit -m "feat(test): testing tests"
[ch-git-hooks-989231] feat(test): testing tests
1 file changed, 1 deletion(-)

Creating a pre-rebase hook

The pre-rebase hook runs before you rebase anything. You can use this hook to disallow rebasing any commits that have already been pushed. The example pre-rebase hook that Git installs does this, although it assumes that next is the name of the branch you publish. You’ll likely need to change that to whatever your stable, published branch is.

/yourgitrepo/.git/hooks

We have covered three git hooks, all of which are are client-side hooks. There are many other hooks you can customize in your project to control certain actions.

Maintaining hooks for a team of developers can be a little tricky because the .git/hooks directory isn’t cloned with the rest of your project, nor is it under version control.

A simple solution to both of these problems is to store your hooks in the actual project directory (above the .git directory). This lets you edit them like any other version-controlled file. To install the hook, you can create a symlink to it in .git/hooks, or you can simply copy and paste it into the .git/hooks directory whenever the hook is updated.
Happy coding!

--

--