Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Automatically tagging builds with Git describe

2010 Zfs Mac

As part of looking after MacZFS, I had to come up with a standard way of representing version numbers of builds. The prior Apple builds, like most Apple products, were sequentially increasing numbers based on some arbitrary reference point in the past. As a result, there was the “102” build (the first initial drop) and the “119” build, the last publicly released version. (There was a “286” build but this was never publicly released as source or binary.)

Since that doesn't tie well with the state of a distributed version control system (where there is no concept of a single anything), I had to invent a new versioning scheme. I chose to base it on the revisions of OpenSolaris (as was), under the onnv tags in the mercurial repository. These too, are centrally numbered releases like onnv_72, onnv_73 etc. but at least they're upstream and which we need to build upon.

As a result, I tag merged copies in GitHub with maczfs_72, maczfs_73 etc. Sometimes this works first off (or I can use a git commit --amend) and sometimes it needs to go through a few subsequent revisions.

Fortunately, I can create a unique point to reference this with git describe. If you run this on any git project, it gives you a tag, plus the number of commits since that tag, and finally the hash (commit id) so you can uniquely pinpoint where you are.

$ git describe

So I'm 5 commits ahead of the maczfs_74 branch, at 169d02a. (The g refers to the fact that it's a git repository, which may help disambiguate for those using other DVCS.)

If I need to re-release something (e.g. based off the maczfs_72 merge point, I can do so by releasing a maczfs_72-1 branch instead. Now the git describe will look like maczfs_72-1-g72c0e09.

From this information, I can derive what version of onnv I'm sync'd against, and how far off the tag I am. This allows me to produce binaries like MacZFS-72.1.7 and MacZFS-74.0.0 and still know where they came from.

I also use this information to post-process the version tag that gets compiled into the zfs executable. First, I get git to tell me where we are, then I use a convoluted AWK script to generate the version numbering text. This is then finally wrapped up in shell invocation in project.pbxproj which uses PListBuddy to write the entries into the Info.plist of the kernel extension. Here's what it looks like:

DESCRIPTION=`git describe --tags --long --match 'maczfs*' 2> /dev/null`
# From AWK script
/maczfs_/ {
        ONNV = $2
        if (NF<5) {
                REL = 0
                COMMIT = max($3,99)
        } else {
                REL = max($3,99)
                COMMIT = max($4,99)
        print ONNV "." REL "." COMMIT

The result is that you can find out where you are by version number using kextstat:

$ kextstat | grep zfs
   98    0 0x1a90000  0x79000    0x78000    com.bandlem.mac.zfs.fs (74.0.0) <7 5 4 1>

From this, we know that the corresponding source that created it is maczfs_74. More information about the arguments are available in the git-describe man page.