Skip to content

git pre-commit Hooks

A very common use case for hooks in git is a "pre-commit" hook. This hook is used to verify the to-be-committed data before it is added to the repository.

One important note: hooks are not part of the repository itself. Everyone can install a hook on it's own checkout of a repository, but by default the hook is not there when you clone/checkout the repository. This avoids security problems by executing arbitrary code during "git commit", or any "git" operation.
Because of this implication it is common that developers install a hook from somewhere in the repository into the ".git/hooks" directory. And in addition, the server side (the repository) can run the same checks during "git push", to enforce the rules.

Hooks in git work in a simple way: whatever program or script is run as the hook has to set a return code. If the return code is "0", git proceeds. If it's not "0", git aborts the operation.

 

Back to the hook: the first problem is how to identify the to-be-committed files? "git diff" lists the files:

git diff --cached --name-only --diff-filter=ACM

The options:

  • --staged: lists all files which are stated for the next commit. --staged is an alias for --cached, both versions can be used.
  • --name-only: lists only the filenames, not the entire diff.
  • --diff-filter: selects what kind of files will be included in the diff.
    • A: Added files
    • C: Copied files
    • M: Modified files

The "git diff" above does not select "Renamed" or "Deleted" files. A renamed file might violate naming rules, in this case you have to include this option as well. And a deleted file is about to be removed from the repository, and most likely does not need to be checked.

Let's put this all together into a small shell script which runs as the git hook. In my example I want to enforce two things:

  1. No double spaces in the file
  2. No spaces at the end of the line

Here is the ".git/hooks/pre-commit" example:

#!/bin/bash

set -e

echo "pre-flight checks:"

file_list=`git diff --cached --name-only --diff-filter=ACM`

exit_status=0
while IFS= read -r file; do
    if [[ "$file" =~ ^content/post/* ]];
    then
        echo "checking file: $file ..."
        if grep -q '  ' "$file";
        then
            echo "Double spaces in file!"
            exit_status=1
        fi

        if egrep -q ' +$' "$file";
        then
            echo "Spaces at end of line!"
            exit_status=1
        fi
    fi
done <<< "$file_list"

if [ "$exit_status" -eq "0" ];
then
    echo "Pre-flight check passed!"
    exit 0
else
    echo "There are some errors ..."
    exit 1
fi

The first part identifies the changed files. The loop runs over all changed files, and checks them for the two conditons. The $exit_status variable is set by any error. Finally the last if-then-else part returns an error if there is any problem in the files.

  • Twitter
  • Bookmark git pre-commit Hooks at del.icio.us
  • Facebook
  • Google Bookmarks
  • FriendFeed
  • Digg git pre-commit Hooks
  • Bloglines git pre-commit Hooks
  • Technorati git pre-commit Hooks
  • Fark this: git pre-commit Hooks
  • Bookmark git pre-commit Hooks at YahooMyWeb
  • Bookmark git pre-commit Hooks at Furl.net
  • Bookmark git pre-commit Hooks at reddit.com
  • Bookmark git pre-commit Hooks at blinklist.com
  • Bookmark git pre-commit Hooks at Spurl.net
  • Bookmark git pre-commit Hooks at Simpy.com
  • Bookmark git pre-commit Hooks at blogmarks
  • Bookmark git pre-commit Hooks with wists
  • wong it!
  • Bookmark using any bookmark manager!
  • Stumble It!
  • Identi.ca

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

Stephan on :

Hey Andreas, check out pre-commit.com. it's an open source tool built by Yelp for exactly this use case, and many more.
Comments ()

Andreas 'ads' Scherbaum on :

I know about this tool, but I find it oversized for the job. It can do too many things.
Comments ()

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.
To leave a comment you must approve it via e-mail, which will be sent to your address after submission.
Form options