Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gnaggnoyil/bb0cd80f079c1d45629285d7f78d7db2 to your computer and use it in GitHub Desktop.
Save gnaggnoyil/bb0cd80f079c1d45629285d7f78d7db2 to your computer and use it in GitHub Desktop.
Revision numbers in Git

Revision numbers in Git

I come from RCS, where revision numbers are easy to insert into files with RCS keyword strings such as $Revision: $, $Id: $ and $Header: $.

There are various posts around of different ways of using revision numbers in Git, e.g. http://stackoverflow.com/questions/4120001/what-is-the-git-equivalent-for-revision-number

When using tags to record release revision numbers, we can use git describe to obtain reasonable-looking revision numbers, e.g. 1.2.1-2-g17880f1, where 1.2.1 is the most recent tag on the current branch, 2 is the number of commits made since the tag, and 17880f1 is the (short) SHA of the current commit (prefixed with g for "git"). These numbers have the benefit of monotonically increasing in the -<number-of-commits>- part, and presumably you would use some sort of meaningful release revision numbers in tags, so they should be fairly easy to understandy by non-technical people (ignoring the -g<SHA> at the end).

Inserting revision numbers in source files

Ideally there would be a way to insert revision numbers, e.g. on installation with make install or the equivalent, to emulate RCS's co behaviour. Ideally it should use standardized tools to do this.

Sometimes I want the version number in a variable, e.g. in Perl

#!/usr/bin/perl
my $VERSION = '1.2.1';

We could instead insert a dummy value that is used as a template, say

#!/usr/bin/perl
my $VERSION = '1.1';

and use a patch like the following (cut-down) unified diff to insert a revision number:

@@ -0 +0 @@
-my $VERSION = '1.1';
+my $VERSION = '1.2.1-2-g17880f1';

This is easy to produce in a shell to incorporate the current git describe revision number, and can be piped directly into patch:

#!/bin/bash
(
  echo "@@ -0 +0 @@"
  echo "-my \$VERSION = '1.1';"
  echo "+my \$VERSION = '$(git describe)';"
) | patch --silent --unified --reject-file=- --output=OUTPUTFILE INPUTFILE

Note the line numbers in the unified diff are both 0. Because patch scans for a matching context, and we have only supplied a single line of context, patch will replace (the first occurrence of) this text anywhere in the file.

Arbitrary RCS-like keywords

Something other than patch is required if we want to replace keywords in a number of places within a file, e.g. with arbitrary RCS-like $Revision: $ strings throughout. One idea is to use sed, e.g.

#!/bin/bash
sed "s/\\\$Revision\\(:[^\$]*\\)\?\\$/\$Id: $(git describe) \$/g" INPUTFILE > OUTPUTFILE

However, the escaping of shell meta-characters in the double-quoted string, along with escaping sed meta-characters, is very ugly and error-prone. If this were incorporated into a Makefile recipe, it would be even uglier with all the $s needing to be escaped by doubling them:

# Makefile
OUTPUTFILE: INPUTFILE
        sed "s/\\\$$Revision\\(:[^\$$]*\\)\?\\$$/\$$Id: $$(git describe) \$$/g" INPUTFILE > OUTPUTFILE

Ugly, eh?

RCS keyword Git equivalent or similar notes
$Revision$ git describe
$Date$ git log -n1 --pretty=%ai or %aD or %ad
$Author$ git log -n1 --pretty=%ae | sed 's/@.*$//' leave out the sed part if you don't mind the full email address
$Locker$ git diff --exit-code || git diff --cached --exit-code || id -nu assume the current user is the locker

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment