Originally posted on my personal blog.
Global Hooks with Git
Introduction
Recently I began to wonder if there was a way to have a collection of git hooks that could run on all of my git projects to save me the trouble of creating/editing hooks in each of my projects. Yes, it is possible to do this for new projects, via the git config --global init.templatedir
command, but I have a lot of pre-existing git projects that I wanted to add a pre-push hook to, and I wanted to be able to make alterations to this hook after the fact that would affect all my projects. Apparently, I'm not the only person who needed this feature, because it was added in git release 2.9.
Details
Adding the global hooks was easy enough, thanks to this stackoverflow answer, but I did run into a couple of caveats after I had the global hooks path set.
git config
To add the path to your global git configuration run the following command:
git config --global core.hooksPath /path/to/my/centralized/hooks
Hook file
The next step is to add your hook file and make it executable.
touch /path/to/my/centralized/hooks/pre-push
chmod a+x /path/to/my/centralized/hooks/pre-push
And then add what ever logic you'd like the hook to execute. I use sonarqube to provide Continuos Inspection to my projects, so I wanted the sonar-scanner
to run on every push. (I highly recommend sonarqube for keeping bugs and code smells out, you should check it out if you're not familiar with it!). I use the fish shell, so you might need a different shebang.
# /path/to/my/centralized/hooks/pre-push
#! /usr/bin/fish
command sonar-scanner
So I created my hook and did a test push, to see that it worked as expected. However, I do have some documentation only and small script projects that don't use the sonar-scanner
. I was getting some ugly error messages when pushing these projects. It didn't fail the push, because I wasn't checking the return code on sonar-scanner
command, but I still wanted to silence these messages, or not run sonar-scanner
at all on projects that didn't need it. That was easy enough to do by checking for the presence of the sonar-project.properties
file before running the scanner.
# /path/to/my/centralized/hooks/pre-push
#! /usr/bin/fish
if test -e ./sonar-project.properties
command sonar-scanner
end
Ok, so now that is running only when it should, but I bumped into another issue. I had some projects that had project specific pre-push hooks that I expected to still be running before a push was executed. I had assumed that adding these global hooks would be in addition to the project hooks, not overriding them. However, that is not the behavior I was wanting; I still wanted any project specific hooks to be executed. The fix for this was to check for the existence of a project level git hook and fire it if it exists. I decided it would make more sense for my use case to fire it before the global hook logic was executed.
# /path/to/my/centralized/hooks/pre-push
#! /usr/bin/fish
if test -e ./.git/hooks/pre-push
command sh ./.git/hooks/pre-push
end
if test -e ./sonar-project.properties
command sonar-scanner
end
Conclusion
So there I had my global hook, that only ran the sonar-scanner
if it was necessary and made sure to also execute any local hooks. I'm sure I've only scratched the surface of the power of this, and I'm looking forward to adding more functionality in the very near future. I'm going to investigate failing the push if the sonarqube quality gate fails, next. To improve my CI/CD work flow. Have any suggestions or ideas for better hooks? Please leave them in the comments below.
Top comments (0)