views:

880

answers:

6

Right now, we are using Perforce for version control. It has the handy feature of a strictly increasing change number that we can use to refer to builds, eg "you'll get the bugfix if your build is at least 44902".

I'd like to switch over to using a distributed system (probably git) to make it easier to branch and to work from home. (Both of which are perfectly possible with Perforce, but the git workflow has some advantages.) So although "tributary development" would be distributed and not refer to a common revision sequencing, we'd still maintain a master git repo that all changes would need to feed into before a build was created.

What's the best way to preserve strictly increasing build ids? The most straightforward way I can think of is to have some sort of post-commit hook that fires off whenever the master repo gets updated, and it registers (the hash of) the new tree object (or commit object? I'm new to git) with a centralized database that hands out ids. (I say "database", but I'd probably do it with git tags, and just look for the next available tag number or something. So the "database" would really be .git/refs/tags/build-id/.)

This is workable, but I'm wondering if there is an easier, or already-implemented, or standard/"best practice" way of accomplishing this.

A: 

I'd use "Labels" Create a label whenever you have a successful (or even unsuccessful) build, and you'll be able to identify that build forever. It's not quite the same, but it does provide those build numbers, while still providing the benefits of distributed development.

foxxtrot
+3  A: 

git tag may be enough for what you need. Pick a tag format that everyone will agree not to use otherwise.

Note: when you tag locally, a git push will not update the tags on the server. Use git push --tags for that.

webmat
+2  A: 

You should investigate git describe. It gives a unique string that describes the current branch (or any passed commit id) in terms of the latest annotated tag, the number of commits since that tag and an abbreviated commit id of the head of the branch.

Presumably you have a single branch that you perform controlled build releases off. In this case I would tag an early commit with a known tag format and then use git describe with the --match option to describe the current HEAD relative to a the known tag. You can then use the result of git describe as is or if you really want just a single number you can use a regex to chop the number out of the tag.

Assuming that you never rewind the branch the number of following commits will always identify a unique point in the branch's history.

e.g. (using bash or similar)

# make an annotated tag to an early build in the repository:
git tag -a build-origin "$some_old_commitid"

# describe the current HEAD against this tag and pull out a build number
expr "$(git describe --match build-origin)" : 'build-origin-\([0-9]*\)-g'
Charles Bailey
A: 

As you probably know, git computes a hash (a number) that uniquely identifies a node of the history. Using these, although they are not strictly increasing, seems like it would be good enough. (Even better, they always correspond to the source, so if you have the hash, you have the same code.) They're big numbers, but mostly you can get by with 6 or so of the leading digits.

For example,

That bug was fixed at 064f2ea...

Denis Bueno
Ok, but I have 1a92b6. Do I have the bugfix?
sfink
git rev-list 1a92b6 | grep 064f2ea --> if this gives something, you've got it; otherwise you don't.
Denis Bueno
+9  A: 

I second the suggestion of using git describe. Provided that you have a sane versioning policy, and you don't do any crazy stuff with your repository, git describe will always be monotonic (at least as monotonic as you can be, when your revision history is a DAG instead of a tree) and unique.

A little demonstration:

git init
git commit --allow-empty -m'Commit One.'
git tag -a -m'Tag One.' 1.2.3
git describe    # => 1.2.3
git commit --allow-empty -m'Commit Two.'
git describe    # => 1.2.3-1-gaac161d
git commit --allow-empty -m'Commit Three.'
git describe    # => 1.2.3-2-g462715d
git tag -a -m'Tag Two.' 2.0.0
git describe    # => 2.0.0

The output of git describe consists of the following components:

  1. The newest tag reachable from the commit you are asking to describe
  2. The number of commits between the commit and the tag (if non-zero)
  3. The (abbreviated) id of the commit (if #2 is non-zero)

#2 is what makes the output monotonic, #3 is what makes it unique. #2 and #3 are omitted, when the commit is the tag, making git describe also suitable for production releases.

Jörg W Mittag
+2  A: 

With Mercurial you can use the following command :

# get the parents id, the local revision number and the tags
[yjost@myhost:~/my-repo]$ hg id -nibt
03b6399bc32b+ 23716+ default tip

See hg identify

yanjost