Skip to content

Roll your own git hook

As part of setting up tools to run in our CI pipeline I also setup a git pre-pushhook to run the same tools automatically in the local context. Git provides a variety of hooks as documented in the scm book, and they can be used to reliably automate different parts of your workflow.

In addition to the official docs this page has a nice summary

Code

The pre-push hook I built for our project looks like:

#!/bin/sh
PROJECTROOT=$(git rev-parse --show-toplevel)  
echo "Running pre-push hook for${PROJECTROOT}"
dotnet restore $PROJECTROOTecho "Running resharper formatter"  
dotnet jb cleanupcode --verbosity=ERROR --config=$PROJECTROOT/.config/cleanup --settings=$PROJECTROOT/.editorconfig --no-buildin-settings $PROJECTROOT/AMS.sln
formatted=$(git status --porcelain=v1 2>/dev/null | wc -l)  

$formatted
echo "Running dotnet resharper inspector"  
dotnet jb inspectcode --verbosity=ERROR AMS.sln -p=$PROJECTROOT/.editorconfig -o=$PROJECTROOT/reports/resharperInspect.xmlpwsh $PROJECTROOT/tools/CheckResharperInspection.ps1  

if [[ $? -eq 0 ]]  
then  
 echo "Running resharper dupe finder"  
else  
 echo "Inspector Errors Found"  
 exit $?  
fi

dotnet jb dupfinder --verbosity=ERROR AMS.sln -o=$PROJECTROOT/reports/resharperDupFinder.xmlpwsh $PROJECTROOT/tools/CheckDupeFinder.ps1  

if [[ $? -eq 0 ]]  
then  
 echo "Running dotnet test"  
else  
 echo "Dupe Errors Found"  
 exit $?  
fi

dotnet cake --target=docker-bg  
dotnet cake --target=dotnet-test  

if [[ $? -eq 0 ]]  
then  
 dotnet cake --target=docker-down  
 echo "Go go go!"  
else  
 dotnet cake --target=docker-down  
 echo "Test failed"  
 exit 1  
fi

The first thing that should stand out is that this is just a shell script. Git hooks are just that, making it easy to use shell, python, powershell or other tools with your hook. Write the script, link it to .git/hooks.

Script Breakdown

In this script the first thing I do is find the root of our project. This makes it easy to reference paths in a manner compatible with scripts and tools that are used throughout in other parts of our workflow.

Install

Since the hook above is just a shell script I like to keep it (and other hooks) in a tools subdirectory in the root project directory. Because git expects hooks to be under .git/hooks we can make it executable with a symlink.

ln -s -f ../../tools/pre-push.sh .git/hooks/pre-pushWith this in place we get feedback before each push so that we don’t have to correct linting issues later, and we have can be confident our commit(s) will run through CI successfully.

Wrapping Up

While you may have heard of projects like pre-commit or husky rolling your own hook is relatively straight forward. While wrappers may help with complex hook setups I personally like the low amount of indirection and abstraction that helps with debugging when rolling your own.