A githooks example, and how to share it with the team

florianbaba

Florian Baba

Posted on March 14, 2021

A githooks example, and how to share it with the team

Introduction

Regarding githooks, I had 3 different goals:

  1. šŸ“œ Verify that my commits respect the expected format (hook nĀ°1)
  2. šŸ”§ Check unit tests are green before every git push (hook nĀ°2)
  3. šŸ‘„ Share these hooks with my team

A bit of context

Just for the record, my project was made with Symfony/PHP, and launched via docker/docker-compose.

But since the main goal here is to use githooks, you can adapt following lines for your own context and needs šŸ˜ƒ

ā„¹ļø Note: Once a git init is made on your project folder, you can find githooks examples in ./.git/hooks in folder as .sample files.

Let's do it

Step 1 - šŸ“œ Verify commit-message format

With my team, we decided to use specific commit formats in order to facilitate the way to consult our git history.

Here are the formats:

## Example of a commit linked to a specific ticket
[PSBO-723] An amazing commit message

## Example of a commit linked to a hotfix
[hotfix] A hot message for a hot commit
Enter fullscreen mode Exit fullscreen mode

First, I need to create a regex that matches only these formats:

^\[(hotfix|\w+\-[0-9]+)\]( \w+)+$
Enter fullscreen mode Exit fullscreen mode

Then I have to create the githooks that will check the commit message format every time I will try to commit.

To do it I create the hook file as .git/hooks/commit-msg in my project folder:

#!/usr/bin/env bash

echo "Checking commit-message format..."

## the first arg is the path to the git commit temporary file
TEMPORARY_FILE_PATH=$1

## get commit-message from the temporary file
COMMIT_MSG=`head -n1 $TEMPORARY_FILE_PATH`

## init regex to match commit-message format
REGEX="^\[(hotfix|\w+\-[0-9]+)\]( \w+)+$"

## checking commit-message format
if ! [[ $COMMIT_MSG =~ $REGEX ]];then
    echo -e "Your commit-message format is not valid:\n$COMMIT_MSG\n"
    echo "Valid format examples:"
    echo "[PSBO-123] My commit message"
    echo "[hotfix] My commit message"
    exit 1
else
    echo "Well done! Your commit-message is valid."
    exit 0
fi

Enter fullscreen mode Exit fullscreen mode

Once done, don't forget to give to the file the right to be executed.

sudo chmod +x .git/hooks/commit-msg
Enter fullscreen mode Exit fullscreen mode

Let's test the hook

Now, if I try to commit with an invalid message:

git commit -m "Yehaaaa"
Enter fullscreen mode Exit fullscreen mode

It returns:

Checking commit-message format...
Your commit-message format is not valid:
Yehaaaa

Valid format examples:
[PSBO-123] My commit message
[hotfix] My commit message
Enter fullscreen mode Exit fullscreen mode

And the commit is canceled, as expected! šŸŽ‰

If I try to commit with a valid message:

git commit -m "[PSBO-456] It's a valid one this time"
Enter fullscreen mode Exit fullscreen mode

It returns:

Checking commit-message format...
Well done! Your commit-message is valid.
Enter fullscreen mode Exit fullscreen mode

And the commit is done! āœ”ļø

Step 2 - šŸ”§ Launch unit tests before each git push

Let's do it again!
Since I want to check unit tests before pushing my code, I will create a hook file as .git/hooks/pre-push:

#!/usr/bin/env bash

echo "Checking unit-tests..."

## checking unit-tests
cd ./infra || exit
if sudo docker-compose run php bin/phpunit;then
    echo "Well done, unit-tests are green!"
    echo "'git push' is now done."
    exit 0
else
    echo "Unit-tests failed, therefore the push is canceled."
    echo "Please fix them before pushing again."
    exit 1
fi

Enter fullscreen mode Exit fullscreen mode

Once again, I need to give this hook file the right to be executed.

sudo chmod +x .git/hooks/pre-push
Enter fullscreen mode Exit fullscreen mode

So, let's check if it works in case my unit tests are failing.

First, I changed the code of a unit test so that it fails.
Now I try to git push to trigger the hook:

git add .
git commit -m "[hotfix] Breaking unit-tests"
git push origin develop
Enter fullscreen mode Exit fullscreen mode

It returns

Checking unit-tests...
Creating infra_php_run ... done

Testing Project Test Suite
F                                                                   1 / 1 (100%)

There was 1 failure:

1) App\Tests\Util\CalculatorTest::testCalculate
Failed asserting that 15 is identical to 16.

/var/www/tests/Util/CalculatorTest.php:31

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
ERROR: 1
Unit-tests failed, therefore the push is canceled.
Please fix them before pushing again.
Enter fullscreen mode Exit fullscreen mode

Tests failed, so the push is canceled, seems good! šŸ‘

OK, this time I fixed the code of the unit test.
Then I push to trigger the hook once again:

git add .
git commit -m "[hotfix] Fixing unit-tests"
git push origin develop
Enter fullscreen mode Exit fullscreen mode

It returns

Checking unit-tests...
Creating infra_php_run ... done

Testing Project Test Suite
.                                                                   1 / 1 (100%)

OK (1 test, 1 assertion)
Well done, unit-tests are green!
'git push' is now done.
Enter fullscreen mode Exit fullscreen mode

Unit-tests are green, so the push was validated and done! This hook works as planned! šŸ’ƒ

Step 3 - šŸ‘„ Share githooks with the team

Now, my hooks are ready!

But unfortunately I can't share them with the team.

Why that?
Because githooks are ignored by git (as every other file in .git folder), therefore they can't be added to the index or be commited in anyway...

Unless we do some little magic! šŸŽ© šŸ°

ā„¹ļø Note: There are multiple solutions to solve this issue, I picked this one because I found it smart and easy to set up.

So to do the magic, I'm going to create my own githooks folder in the root path of the project (not in the .git folder):

## I create my own githooks folder
mkdir .githooks

## Then, move the githooks I created in this new folder
mv .git/hooks/commit-msg .githooks/
mv .git/hooks/pre-push .githooks/

## Don't forget to give "execute" right to the files, if not already done
sudo chmod +x .githooks/*
Enter fullscreen mode Exit fullscreen mode

Now, I just need to tell git where to find my githooks files:

## Specify a folder for hooks (only available for git version >= 2.9)
git config core.hooksPath .githooks
Enter fullscreen mode Exit fullscreen mode

And it's done!

From now one, I can commit these hooks since there are no longer ignored by git, so my teammates will be able to use them.

Conclusion

My githooks work, and I can share them with my team, it's all good! šŸŽ‰ šŸ’„

Hope this helped you find out how githooks work and how powerful they can be.

šŸ’– šŸ’Ŗ šŸ™… šŸš©
florianbaba
Florian Baba

Posted on March 14, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related