Git Hooks: Enforce Commit Message and Branch Name

December 1, 2021 • 3 min read

Written in: EnglishTürkçe

If you want to standardize things among your team, you may need to enforce strict rules. Some examples of rules might be for git are:

  • Branches must be created as ISSUE-0000/feature-name.
  • All commit messages must start as ISSUE-0000 (Jira issue id).

In this post, I will show you how we can add the two rules I mentioned using git hooks.


There are multiple git hooks that work in different stages. We will use two client-side hooks for our rules.

  • pre-commit: This hook is invoked by git-commit, and can be bypassed with the --no-verify option. We will use this hook for checking the branch name before committing.
  • commit-msg: This hook is invoked by git-commit and git-merge, and can be bypassed with the --no-verify option. It takes a single parameter, the name of the file that holds the proposed commit message. We will use this hook for checking the commit message. And we will modify the commit message if needed.

Creating Hooks Folder

Go to your home directory and create a folder named hooks. And create hook files.

mkdir ~/hooks
cd ~/hooks

touch pre-commit
chmod +x pre-commit

touch commit-msg
chmod +x commit-msg

Restricting Branch Names

We will accept branch names as ISSUE-0000/feature-name but we have to consider also other branch names like main, develop, release etc. For this, we can use the following regular expression.

REGEX_ISSUE_ID="^(ISSUE-[0-9]+\/([a-zA-Z0-9]|-)+|develop|main|release"

We also need the branch name:

git rev-parse --abbrev-ref HEAD

That’s it! We have regex and we have branch name. We will check for branch name starts with ISSUE-0000/feature-name or develop or main or release. If our check fails we will echo our error message and exit with exit code 1.

pre-commit

#!/bin/bash

REGEX_ISSUE_ID="^(ISSUE-[0-9]+\/([a-zA-Z0-9]|-)+|develop|main|release"

ISSUE_ID_IN_BRANCH=$(echo $(git rev-parse --abbrev-ref HEAD) | grep -o -E "$REGEX_ISSUE_ID")

if [[ -z "$ISSUE_ID_IN_BRANCH" ]]; then
    echo "[pre-commit-hook] Your branch name is illegal. Please rename your branch with using following regex: $REGEX_ISSUE_ID"
    exit 1
fi

Restricting Commit Messages

Steps are similar to restricting branch names. But if there is no issue id in the commit message, we will look at the branch name and try to get it from there. If the issue id is also not in the branch name, we will throw an error.

REGEX_ISSUE_ID="^(ISSUE-[0-9]+|Merge|hotfix)"

Our first argument $1 gives us the commit-msg file. We can read the commit message with the following command:

cat "$1"

We have regex and we have to commit message name, and from the last step, we know how to get branch name. We will check for commit message starts with ISSUE-0000 or Merge or hotfix.

If the commit check fails we will check our branch name and parse the issue id and insert to commit message.

If our check fails again we will echo our error message and exit with exit code 1.

commit-msg

#!/bin/bash

REGEX_ISSUE_ID="^(ISSUE-[0-9]+|Merge|hotfix)"
ISSUE_ID_IN_COMMIT=$(echo $(cat "$1") | grep -o -E "$REGEX_ISSUE_ID")

if [[ -z "$ISSUE_ID_IN_COMMIT" ]]; then
    BRANCH_NAME=$(git symbolic-ref --short HEAD)
    ISSUE_ID=$(echo "$BRANCH_NAME" | grep -o -E "$REGEX_ISSUE_ID")

    if [[ -z "$ISSUE_ID" ]]; then
        echo "[commit-msg-hook] Your commit message is illegal. Please rename your branch with using following regex: $REGEX_ISSUE_ID"
        exit 1
    fi

    echo "$ISSUE_ID | $(cat "$1")" > "$1"
fi

Usage

Go to the project folder and run the following command to use your hooks. You need to make this for every project that you want to use hooks.

cd <your-team-repository>
git config core.hooksPath ~/hooks

Sharing With Team Members

You need to share your ~/hooks folder. You can share with a git repository or you can send the folder directly to your team.