Global Hooks with Git
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.
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.
To add the path to your global git configuration run the following command:
git config --global core.hooksPath /path/to/my/centralized/hooks
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
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.
Date Published: 17 February, 2019