Build numbers in interpreted code

When I write a program I like to include a build number in the version. Usually I go version.revision.build. The version only ever gets bumped for things that are practically a complete rewrite, and sometimes not even then. The revision gets bumped for new features or major bug fixes and the build gets bumped for every compile.

This gives the huge of advantage of being able to identify the exact time a particular version of a program was created and thus make bug finding easier.

For compiled code this works really well, I just have the build process increment the number somehow. For interpreted code, such as python, however there is no build process. So how do I make sure the build number gets incremented every time? There is no way I would remember to increment it manually.

When I was using subversion I hacked something together using $LastChangedRevision$, so the build number was based on the most recent svn commit number. It worked well enough and I was happy.

Now however I’m switching to git, which doesn’t have keywords like CVS and Subversion so I’m a bit stumped. I tried hacking a script that auto-increments a number then runs a git commit, but not only is it logically flawed, but it relies on me remembering to run it rather than direct git commands which is never going to be reliable.

Maybe I could do something with the current date, but again that would rely on me running something. Probably repo hooks are the answer somehow but I’ve no idea how. The build no. itself needs to be stored in git so as to sync between computers. Can a git repo hook update a file then commit that update back to itself automatically (without an infinite recursion destroying the repo)?

Update (2009-04-05): I’ve worked out how to generate an auto-incrementing number via git hooks. Use the following script as a pre-commit hook (save as .git/hooks/pre-commit). It’s setup for python but it could easily be adapted for whatever language you need.

#!/bin/bash
#
# Called by git-commit with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# This script will automatically increment the __revision__ number in
# the file version.py on every git commit.

f="$GIT_DIR/../version.py"

REVISION=$(grep ‘^__revision__’ $f | sed ‘s/^__revision__ = //’)
#echo "Current revision = $REVISION"
let REVISION=$REVISION+1
#echo "New revision = $REVISION"
sed -r "s/^(__revision__ = )([0-9]+)$/\1$REVISION/" < $f > $f.new
mv $f.new $f
git add $f