How to derive application build version string with Git's `describe` command?
Asked Answered
L

4

19

I want to compose application build version that is automatically derived from the Git branch name I am on (when building) and the number of commits since the branch has diverged. I believe this will be unique for any commit in my Git repository? Branch names are unique, and commits are linked to each other along a branch? If and when I tag a commit, I can also have the version be prefixed with that tag.

In a way git describe does what I want, but it does not include the branch name I am on, and it includes abbreviated commit SHA-1 hash, which I don't think I need as it does not add anything to the entropy of the string and may be redundant (I may be wrong here, so please correct me).

What are my options? And am I thinking in the right direction here at all? I am just a bit tired of appending numbers to versions when I have more important things to deal with with regards to software development.

I never build with a dirty working tree, by the way. I.e. I always commit changes to the repository before building a public release.

Lenny answered 21/7, 2010 at 15:6 Comment(0)
A
13

The thing you have you to understand about git is that branches are essentially merely commit bookmarks. The fact that you were on the foo branch when you made the 0deadbeef commit is immaterial to the commit itself; the branch is not part of its identity.

(Mercurial bakes the branch name into the commit. In a variety of ways, this is inferior, as Dustin Sallings explains.)

Even assuming that git describe would just use the currently checked out branch – if you have a mergy history, there could be multiple paths leading to the same most recent tagged commit that git describe would use. So there isn’t even necessarily any one branch.

Another note: you may object that even if “3rd commit from tag X” is ambiguous in the general case, git describe could just look at the graph and figure out whether it is ambiguous and if not, leave out the hash. However, there is nothing stopping anyone starting a branch on top of that tag at a later time – so then your describe string would become ambiguous retrospectively.

Bottom line is that the only unambiguous identifier of a commit is its hash. So that must be in there. What git describe does is add some redundant (and in case of the commit number, ambiguous) information that makes the description more useful to the kind of spatial/relational comprehension that humans orient themselves with, within the confines of the Git model.

Antheridium answered 21/7, 2010 at 21:2 Comment(1)
Yes, I have realized this property of branches now. With it, it would be ambigous to specify a branch indeed.Lenny
H
12

Here is what I use:

echo "`git symbolic-ref HEAD 2> /dev/null | cut -b 12-`-`git log --pretty=format:\"%h\" -1`"

It produces something like:

master-6de772e

As noted by Aristotle, in actuality the SHA-1 by itself is all that is necessary and sufficient to provide an unambiguous build tag, as well as full information regarding the developmental historical context. Everything else is redundant, in the sense that any information they provide can be figured out or derived from the SHA-1. However, humans might like the supplementary contextual information of the actual branch immediately evident as well (or, at least, this human does), and hence the embedding of the branch name into the label. For this reason also (i.e. immediate human parsing of the information), most of my projects also use a longer build identity 'description' that includes the date and time of the commit that the build was based on in addition to the build identity 'label' given above.

Here answered 25/7, 2010 at 17:6 Comment(3)
Ok, given how I think what I ask for may simply be impossible, I will have to resort to abbreviated hashes. I won't need the branch name then, by the way.Lenny
@jeet can you please say how to include that in the make file? I tried '@echo (your-answer) > git-version.h' but this does not workBichromate
@Bichromate I use autobuild, so the Makefile.am looks like this: github.com/jeetsukumaran/Ginkgo/blob/master/ginkgocc/…Here
T
7

Official releases should have a tag with their version number. In this case I suggest the following approach:

  1. If the current commit has a tag, use that tag
  2. If no tag is available, use the branch name and the SHA1-key

This single command should work:

git describe --exact-match 2> /dev/null || echo "`git symbolic-ref HEAD 2> /dev/null | cut -b 12-`-`git log --pretty=format:\"%h\" -1`"
Turgeon answered 2/12, 2011 at 15:3 Comment(0)
L
6

git describe --long would always output version number like this: v1.2-10-gdeadbee, which means 10th commit since annotated tag 'v1.2' that points at commit with shortened SHA-1 'deadbee'. So all you have to do is to tag branch start (branching point of a branch) e.g. <branch>-start.

The abbreviated commit SHA-1 hash is required to distinguish between ambiguous situations, because "3rd commit since tag 'x'" (for example) does not uniquely distinguish a commit; there can be more than one commit that fits mentioned description in the presence of nonlinear, branchy development. For example in the situation shown on the ASCII-art diagram below both commits marked with * fits "3rd commit since tag 'x'" description.

          /-.---*---.-\                   
         /             \                  
.---x---.---.---*---.---M---.    <--- branch

Note that in "merged in" case as shown above you can't use branch name to distinguish between those two commits with the same description.

So what you have to do would be to take git describe --long output (the --long option is here to avoid ambiguities with parsing, see git describe manpage), parse it, and add current branch info (from e.g. git symbolic-ref HEAD, not from pasing git branch output) yourself.

Leicestershire answered 21/7, 2010 at 17:30 Comment(5)
I am well aware that a "3rd commit since point N" would be ambigous, that is why I was asking whether having a branch name present will remove the ambiguity. In your example above, both are 3-rd commits indeed, but they are on separate branches. One could therefore be described as v1.2-10-A and another v1.2-10-B, where A and B are branch names. Which is what I was curious about, among other things.Lenny
@amn: not in "merged in" case, branch name would not help - see modified diagram. Branches are ephemeral.Competency
Well, 'M', as merged from the 'other' branch, is on master branch (I am guessing the merge was done with 'git merge other' while on 'master'), so it can still be uniquely identified as 7-th (initial commit is 1st) commit on branch 'master', no? Am I missing something? Could you provide an example where it really breaks?Lenny
@amn: The problame is not with 'M', but with commits marked '*' on diagram, both of which are "3rd commit since tag 'x'" (or "5th from beginning, counting initial commit as 1st"), and both of which are on branch 'master'.Competency
Jakub, even though both commits marked with * are 3rd from tag x, they are on separate branches. I never said I want to count from tags by the way, I said I can prefix the tag to version, if needed.Lenny

© 2022 - 2024 — McMap. All rights reserved.