Recently I made a mistake of committing a conflict marker and pushing that code to Github.

That is when I thought that I could have a easily avoided this if I had added a git-hook to warn me if the code that I commit had conflict markers. Here is how you would set up something like that.

What are git-hooks?

In case you are new to git-hooks, it is a way by which git lets to hook into the different things that git does. You can write git-hooks to do a lot of things. You can modify a commit message to add some additional info using a git hook. You can print out extra stuff on commit(what we will be using) or push or any such operation.

Git hooks are small executables that you place in .git/hooks directory of your repo. If you were to check your .git/hooks directory right now for any repo, you can see a few files which ends with *.sample. Those are samples that git by default puts there so that you can see what it can probably do.

Our solution

What we are going to do is to create a pre-commit hook which will show something like this. It will give us a big bold red warning when we try to commit a piece of code that contains conflict markers in it.

conflict-marker

tldr;

Place this piece of code as .git/hook/pre-commit and make it executable using chmod +x .git/hooks/pre-commit

#! /bin/sh

RED=$(tput setab 1)
NORMAL=$(tput sgr0)

CONFLICT_MARKERS='<<<<<<<|=======|>>>>>>>' 
CHECK=$(git diff --staged | grep "^+" | grep -Ei "$CONFLICT_MARKERS" -c)
if [ "$CHECK" -gt 0 ]
then
    echo "$RED WARNING $NORMAL Conflict markers sill preset"
    git diff --name-only -G"$CONFLICT_MARKERS"
    # uncomment the below line if you need the commit to not go through at all
    # exit 1
fi

Explanation

OK, that might look like a mess, but let me explain.

After the usual shebang, we define a variable called CONFLICT_MARKERS with the possible conflict markers separated by |. The reason why we are separating the markers by | is because we use them in grep and in regex land it means, match one of <<<<<<<, =======, >>>>>>>.

On the next line we do the actual check to see if the conflict markers are present in the code using grep. In this line what we do is we pipe the diff of staged commits through grep '^+' which will filter out only the lines which were added and that in turn gets passed to the next grep which counts the number of times any of those conflict markers appear in the added lines in the diff and store the count to a variable CHECK.

Next line is an if check to see if the value in variable CHECK is greater than 0. And if it is greater than 0, we show the warning and a list of files which has conflict markers in them.

You can prevent the commit from ever happening if you uncomment exit 1. But I would personally not recommend this unless you add a way to bypass this, maybe using something like and env variable. In some rare cases where you might need one of those conflict markers in your code, you will not be able to make the commit without modifying this code.

Usage

As mentioned above, you can put this code in .git/hooks/pre-commit of any git repo where you need this check.

You can also put this in $HOME/.git_template/hooks/pre-commit to enable this is all the new git repos you create. Any hooks you place here will be copied over to the hooks dir in the new git repos you create.