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).
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.
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 |
---|---|---|
git describe | ||
git log -n1 --pretty=%ai | or %aD or %ad | |
git log -n1 --pretty=%ae | sed 's/@.*$//' | leave out the sed part if you don't mind the full email address | |
git diff --exit-code || git diff --cached --exit-code || id -nu | assume the current user is the locker |
http://stackoverflow.com/a/1796675