GIT Hack: Prevent pushing to master

Git has this great feature whereby you can execute arbitrary scripts whenever something happens on your git repository. A common use case for this is a pre-receive hook on the remote repository which prevents people with access from doing destructive actions, like force pushing, which are incredibly easy to do by accident.

Many projects use GitHub as their remote repository, and as GitHub is a service, they do not permit you to upload arbitrary scripts to run on their servers. Makes sense, but how then can you protect your codebase?

Turns out, from version 1.8.2, Git has a new pre-push hook that lets you do the same thing on your local repository. It's not as handy as setting it up on the remote for all your users, but it does allow you the developer to protect yourself from... yourself.

Setup the hook

For any repository you want to protect, you need to create a new file called pre-push in the .git/hooks directory and make sure the file has permission to be executed. Inside the file, you'll add the script you want to run, here's the one I use:

#!/bin/bash

protected_branch='master'  
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

if [ $protected_branch = $current_branch ]  
then  
    read -p "You're about to push master, is that what you intended? [y|n] " -n 1 -r < /dev/tty
    echo
    if echo $REPLY | grep -E '^[Yy]$' > /dev/null
    then
        exit 0 # push will execute
    fi
    exit 1 # push will not execute
else  
    exit 0 # push will execute
fi  

This checks if the current branch is master, and if so it will prompt you to confirm what you're doing. It doesn't detect whether you're doing a normal push, or a force push, as I prefer to have the confirmation on any push to master. This script is borrowed heavily from scripts by pixelhandler and Itty Bitty Labs. For anyone wondering, the weird use of grep is so that this works on Windows as well as *nix systems.

Once you've added this script to your .git/hooks/pre-push file, any push command which operates on the master branch will require confirmation. Simple, but very effective.

Note: If the confirmation doesn't appear for you, please check that you have a git version higher than 1.8.2 (run git --version on the command line) and also check that the pre-push file is executable (run chmod +x pre-push on the command line) and try again :)