Using Git commit hooks to prevent stupid mistakes

I’m pretty prone to making stupid mistakes all the time. I think its a mixture of being busy, and being a natural scatter brain. In any case, mistakes happen, and thankfully over time developers have come up with a number of ways to combat mistakes. These usually take the shape in automated toolds. Unit tests are a great way to automated tool to help prevent stupid mistakes from happening, Git commit hooks are another. Git hooks are shell or other scripts that you install in your repo, and git will run them at certain points in time. One nice advantage of git commit hooks is you can install them locally and you can avoid publishing the stupid mistake you might make.

For me, I quite often commit debugger; statements in my javascript code. I want to not do that anymore so I created the following hook in .git/hooks/pre-commit

Show Plain Text
  1.  
  2. #!/bin/sh
  3.  
  4. if git-rev-parse --verify HEAD >/dev/null 2>&1; then
  5.     against=HEAD
  6. else
  7.     against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
  8. fi
  9.  
  10. for FILE in `git diff-index --check --name-status $against -- | cut -c3-` ; do
  11.     # Check if the file contains 'debugger'
  12.     if [ "grep 'debugger' $FILE" ]
  13.     then
  14.         echo $FILE ' contains debugger!'
  15.         exit 1
  16.     fi
  17. done
  18. exit
  19.  

After creating the file its important to make it executable with chmod +x .git/hooks/pre-commit or git won’t run your script. Git hooks are installed on a per-repo basis, which is kind of bad. Its also kind of good, in that you can easily install your own suite of git hooks and no-one will be the wiser. There are a number of hooks available in git, and you can learn all about them in Pro Git

Comments

What is the purpose of the conditional at the beginning with the fallback to the magic refname?

Justin on 20/4/11

At Disqus we’re running JSHint as part of our pre-commit hook. You can configure it to reject development-y function calls (like console.log), as well as enforce a number of good practices.

Speaking of which, static comments Mark? For shame …

Ben on 21/4/11

That’s a cool idea, Ben, using it to look for console.log – that’s hands-down one of my most annoying habits as far as commits are concerned.

I do a similar thing to this, but the stupid mistake I’m protecting against is committing configuration patches, which helps me keep apps platform/configuration agnostic (shameless self-plug: ) http://tndy.me/h3GlDE

Jasper on 25/4/11

Justin: The magic refname is the initial tree object present in every git repo, its in the example pre-commit hook, and it would keep your hook working even on a brand new repo.

mark story on 30/4/11

Hey Mark, I think this line

if [ “grep ‘debugger’ $file” ]

should read

if [ “grep ‘debugger’ $FILE” ]

Kevin van Zonneveld on 1/8/11

Kevin: You’re totally right. Thanks :)

mark story on 7/8/11

Since it greps the file without regard for what has been staged, I believe it will reject debugs that aren’t actually about to be committed, if you git add a file, then add debug statements but don’t git add them, then try to commit. Probably not a big deal.

I made a similar hook in Ruby that only looks at what has been added: https://github.com/henrik/dotfiles/blob/master/githooks/pre-commit

Henrik N on 7/10/11

Have your say:

*
* You can use Textile markup, but be reasonable