Tuesday, 15 December 2009

The git equivalent of svnversion

I've been happily using git as my version control weapon of choice for some time now. It's integrated into my automatic build, test, and release scripts neatly. The world is a nice place.

Except, I've not really found a compelling replacement for Subversion's svnversion. I used to use svnversion in my release scripts to name the final build disk image nicely, something like "fooproject-SVNVERSION.dmg", as well as versioning some of the files inside the image.
What is svnversion?
svnversion is a cute little command line tool that looks in the current working directory to determine which revision of a subversion repository you have checked out. If your head revision is 215, and you have all files checked out at HEAD, then running svnverison you'll get:
pete@solomon > svnversion
If you have some older files, then you'd get something like:
pete@solomon > svnversion
And, if your working copy contains some files with uncommited local changed, then you'd get a helpful M added to the end:
pete@solomon > svnversion
It is possible to get something similar to svnversion using git's git describe command. In some ways it is superior to Subversion's simple monotonically incrementing numbers, in some ways inferior. By necessity, it works differently from svnversion.

git describe looks at the git revision you have checked out, and produces the name of the nearest tag followed by the number of commits since that tag, and a partial SHA-1 value of the current commit. This is relatively cute:
pete@solomon > git describe
However, there are issues:
  • Firstly, it doesn't mark whether there are local uncommitted modifications in your local tree.
  • And the partial SHA-1 at the end may not always be valid. If your project gets large enough that more characters are required to unambiguously identify one SHA-1 value all older "git describe"s will no longer uniquely identify a revision.
We can't fix the latter issue, but we can tweak a little to add some "M" love to our git description.

Try this little bit of bash scriptery:
GITVERSION=`git describe`
GITMODIFIED=`(git st | grep "modified:\|added:\|deleted:" -q) && echo "-M"`

That's a little more useful.

If you know a better way of doing this, I'd love to know!


pclouds said...

Have a look at GIT-VERSION-GEN in Git source code.

Stephen Lacy said...

Take a look at the git docs for describe. You can say "git describe --dirty" to get the behavior you want.