Git hooks are a great way to automate your workflow and to check for faulty commits. I am using them to prevent work-in-progress commits to the master branch (i.e. commits with a line starting with the string WIP) . But wait – this script differs from the sample found in .git/hooks/pre-commit.sample in two ways:
- Only pushes to special heads are inspected. This still allows you to backup your WIP commit on the remote server or to share it with your colleagues but prevents integration into the master branch.
- Only commits which would actually be merged into the master are checked – and not all commits ever pushed. This way, even when a WIP commit was pushed to the master in the past, the script does not prevent you from pushing new commits. The pre-commit.sample would explicitly disallow that.
We have two staging areas in our development environment: All pushes to ready/<any name> or directPatch/<any name> trigger our continuous integration process and eventually merge the changes into our master (which you cannot push to directly). Pushes to <developer acronym>/<any name> are always allowed and do not trigger any merging. So we want to check only the pushes to ready and directPatch. Of course, you might want to adapt the script to your needs:
- Changing the heads to be checked – see line 24
- Changing the word to look for – see line 40
The following hook can be activated by storing it in the file <your repository>/.git/hooks/pre-commit (no file extension)
#!/bin/sh # This hook is called with the following parameters: # # $1 -- Name of the remote to which the push is being done # $2 -- URL to which the push is being done # # Information about the commits which are being pushed is # supplied as lines to the standard input in the form: # # <local ref> <local sha1> <remote ref> <remote sha1> # # This sample shows how to prevent push of commits where the # log message starts with "WIP" (work in progress) and is pushed # to a refs/heads/ready or refs/heads/directPatch remote="$1" url="$2" z40=0000000000000000000000000000000000000000 IFS=' ' while read local_ref local_sha remote_ref remote_sha do if [[ $remote_ref != refs/heads/ready/* ]] && [[ $remote_ref != refs/heads/directPatch/* ]] then # Do not check the WIP continue fi if [ "$local_sha" = $z40 ] then # Handle delete : else # Only inspect commits not yet merged into origin/master range="origin/master..$local_sha" # Check for WIP commit commit=`git rev-list -n 1 --grep '^WIP' "$range"` if [ -n "$commit" ] then echo "Found WIP commit in $local_ref: $commit, not pushing." exit 1 fi fi done exit 0
Shouldn’t this be a pre-push hook?
Also possible but then you would have to revise all of your previous commits if you accidentally added a NOCOMMIT line in one of them. If you do the check in pre-commit, you get immediate feedback
The problem with a pre-commit hook is that a pre-commit hook doesn’t actually get passed any arguments, nor does it receive any input from standard input.