Werner's own blurbs

Beta release numbering with GIT

17 August 2012 9:31 AM (devel | git)

Given that building software from source code repositories can turn out into a difficult task for non-developers, the distribution of tarballs snapshots is often a sensible thing to do.

The question is how to identify such a snapshot release. My take on that has always been to use the planned version number and suffix it with a string identifying the version as a beta release. With a centralized revision control system, this is quite easy. You can use a suffix like "-svnNNNN" with NNNN being the revision number. The nice thing is that you still have a monotone increasing revision number; that is the user can easily see that "foo-3.4-svn500" is newer than "foo-3.4-svn480".

Now with a decentralized revision control system, this changed. There is no global revision number anymore and any procedure to make one up one would indispensable put in some centralism. However, with GIT there is way to mitigate that. This makes use of the fact that we should have release planning anyway and that releases are tagged in the repository. The "git describe" command may then be used to come up with a revision number:

git describe --match 'foo-[0-9].*[0-9]'

The output might be "foo-3.4-81-g1234567". We are only interested in the third term, which is the number of commits since the commit tagged as "foo-3.4". We use this as a beta revision number.

Now to pour that into code we need some M4 magic for autoconf. What we need to do is to construct a version number at an early autoconf stage, so that the version number is a static string for autoconf. Autoconf is based on M4, which is not that vintage German camera but a macro language developed by Brian Kernighan and Dennis Ritchie. As with all macro languages it is not easy to use but nevertheless very powerful. We don’t use M4 directly but use autoconf provided wrapper macros.

At the top of configure.ac you need to define a new M4 macro. If our next release will be 3.4 we would write:

m4_define(my_version, [3.4])

and that is the only place you need to change for a new version number. Everything else works automagically using the next few lines of code:

m4_define([git_revision], m4_esyscmd([git branch -v 2>/dev/null \
           | awk '/^\* / {printf "%s",$3}']))
m4_define([git_revision_dec],
          m4_esyscmd_s([echo $((0x$(echo ]git_revision[|head -c 4)))]))

This puts the GIT commit id into the m4 macro git_revision and an abbreviated and decimal variant of it into git_revision_dec. Those two macros are not actually required for our system but they are often useful for other purposes. For example git_revision_dec can be used as the build number on Windows platforms.

m4_define([git_betastring],
           m4_esyscmd_s([git describe --match 'foo-[0-9].*[0-9]' --long|\
                        awk -F- '$3!=0{print"-beta"$3}']))
m4_define([my_full_version],[my_version[]git_betastring])

This is the actual code to extract and build the revision suffix. It is pretty straightforward: "git describe" is called and the number of commits since the matching tag extracted. If the number is not zero, the beta suffix is appended to the version number. The final step is to change the AC_INIT call to something like this:

AC_INIT([foo],[my_full_version],[foo-bugs@example.org])

Now after running autoconf you will get a suitable version number. Run the usual "configure" and "make distcheck" to create snapshot tarballs named for example "foo-3.4-beta81.tar.bz2".

If you are finally ready for a release and did your last commit, you merely need to add a tag

git tag -s foo-3.4

and run "autoconf", "configure" and "make distcheck". Et voilà, your "foo-3.4.tar.bz2" is ready. If that works well, you may now push the tag and then update my_version to 3.5 to start a new development cycle.

No responses

Leave a Reply