Introduction
Regarding githooks, I had 3 different goals:
- ๐ Verify that my commits respect the expected format (hook nยฐ1)
- ๐ง Check unit tests are green before every
git push
(hook nยฐ2) - ๐ฅ 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
First, I need to create a regex that matches only these formats:
^\[(hotfix|\w+\-[0-9]+)\]( \w+)+$
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
Once done, don't forget to give to the file the right to be executed.
sudo chmod +x .git/hooks/commit-msg
Let's test the hook
Now, if I try to commit with an invalid message:
git commit -m "Yehaaaa"
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
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"
It returns:
Checking commit-message format...
Well done! Your commit-message is valid.
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
Once again, I need to give this hook file the right to be executed.
sudo chmod +x .git/hooks/pre-push
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
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.
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
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.
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/*
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
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.
Top comments (5)
What a post! I will use this everywhere!
Hey thx, glad you like it :)
It was really useful, thank you !
That's nice, but every devs still need to change their git hooks directory manually.