git-describe

  • Thread starter Lawrence D'Oliveiro
  • Start date
L

Lawrence D'Oliveiro

Discovered yet another nifty Git feature while looking through the docs.

Build scripts often try to automatically determine some kind of revision
number to include with the version info when building a piece of software.
With Subversion, you can use “svn info†to get a revision number that
increments with every commit, that you can use for that.

With Git, there is no real equivalent, since it has no sequence numbers for
anything, every object being identified by its SHA-1 hash, with no sensible
ordering at all.

But if you have tagged some prior revision, the command “git describe --
tags†will generate a string of the form

<tag>-<nr revisions since>-g<part of current revision hash>

For example, looking at the current dvdauthor source tree, the command
returns this

0.7.0-18-g6143744

which means it has been 18 commits since the one I released (and tagged) as
“0.7.0â€, and the hash for the last commit begins with 6143744.

Exercise for the reader: what happens if you don’t specify “--tags�
 
T

Tom Anderson

Discovered yet another nifty Git feature while looking through the docs.

Build scripts often try to automatically determine some kind of revision
number to include with the version info when building a piece of software.
With Subversion, you can use “svn info†to get a revision number that
increments with every commit, that you can use for that.

With Git, there is no real equivalent, since it has no sequence numbers for
anything, every object being identified by its SHA-1 hash, with no sensible
ordering at all.

Mercurial has a very slight edge here, in that as well as the hash-based
changeset IDs, it also has a sequential changeset number. The output of
'hg log' from a trivial demo repository:

changeset: 2:1af3be9856b9
tag: tip
user: admin@initech-dev-19
date: Thu May 26 15:28:30 2011 +0100
summary: keeping things up to daet

changeset: 1:d2a7ea8727e4
user: admin@initech-dev-19
date: Thu May 26 15:26:06 2011 +0100
summary: update

changeset: 0:a9f4a5b5e4ca
user: admin@initech-dev-19
date: Thu May 26 15:25:54 2011 +0100
summary: first commit

The 'changeset' lines have the revision number, a colon, and the first
twelve characters of the changeset ID.

The problem with this is that the numbers record the sequence in which
changesets were added to the current repository - which in the presence of
commits on multiple machines (ie for any realistic development team) means
that the numbers won't be the same in different repositories.

For example, if i create a repository and make an initial commit, the
first changeset gets number 0. If you pull it from me, it will be 0 in
your repository too. If i do some work and commit it, my new changeset
will have number 1. If you do some work and commit, your new changeset
will also have number 1. When you then pull from me, my changeset will
have number 2.

So, numbers are useful and meaningful, but only in the context of one
repository.

If you have a single 'golden master' repository from which you cut
releases, then this may be good enough; you can always relate the number
to that repository, so a higher number always means a later version.

Failing that, you could use a build number which combines the identity of
the repository and the changeset number, but that's rather less useful.

Alternatively, you have some sort of master repository, and give it a
post-changegroup hook that tags every push with a tag constructed from the
local changeset number.
But if you have tagged some prior revision, the command “git describe --
tags†will generate a string of the form

<tag>-<nr revisions since>-g<part of current revision hash>

For example, looking at the current dvdauthor source tree, the command
returns this

0.7.0-18-g6143744

which means it has been 18 commits since the one I released (and tagged) as
“0.7.0â€, and the hash for the last commit begins with 6143744.

In the absence of a master repository, that is substantially more helpful
than what you can do with Mercurial

A bit of googling reveals that someone ported this to Mercurial as an
extension, but it seems to have died.
Exercise for the reader: what happens if you don’t specify “--tags�

States it as revisions from the initial checkin?

tom
 
L

Lawrence D'Oliveiro

The problem with this is that the numbers record the sequence in which
changesets were added to the current repository - which in the presence of
commits on multiple machines (ie for any realistic development team) means
that the numbers won't be the same in different repositories.

Sounds like it’s more equivalent to what you might get out of a “reflog†on
Git. This is a purely personal, interim record of changes to the repository,
which is never pushed/pulled as part of the repository itself, and can be
purged (on demand) at any time.
Mercurial has a very slight edge here, in that as well as the hash-based
changeset IDs, it also has a sequential changeset number.

As soon as I read this, I wondered what would happen to the numbering if you
did the Git equivalent of committing something, then abandoning that commit
(resetting that branch back to a prior commit) and making a new one. This
can’t just arise from mistakes; it’s recommended in the Git docs as a handy
way of saving temporary changes while working om something else.
States it as revisions from the initial checkin?

Actually, no. It turns out there are two different kinds of tags, and which
one is used depends on this option.
 
T

Tom Anderson

Sounds like it’s more equivalent to what you might get out of a “reflogâ€
on Git. This is a purely personal, interim record of changes to the
repository, which is never pushed/pulled as part of the repository
itself, and can be purged (on demand) at any time.

Yes, it's somewhat like reflog. It's a bit more front-and-centre than
reflog is, less of a hidden bonus feature, and it has a model that seems
simpler to me: the numbers count the addition of changesets to the
repository. Every changeset added, by whatever means, gets a number one
higher than the previous one. Whereas reflog, if i've understood it right,
numbers revisions by how recently they were the head. So the numbers
change when you change what's head. I may have misunderstood this.

In the sense that it's personal and never pushed or pulled, though, yes,
it's just like reflog. I wouldn't really call it interim.
As soon as I read this, I wondered what would happen to the numbering if
you did the Git equivalent of committing something, then abandoning that
commit (resetting that branch back to a prior commit) and making a new
one. This can’t just arise from mistakes; it’s recommended in the Git
docs as a handy way of saving temporary changes while working om
something else.

It's also the normal way of working in Mercurial (as long as 'resetting'
doesn't mean 'throwing away'). Here's a brief session that illustrates
what happens:

$ hg init branchy
$ cd branchy/
$ date >first
$ hg add
adding first
$ hg commit -m 'the beginning'
$ date >second
$ hg add
adding second
$ hg commit -m 'continuation'
$ # no, too boring, try again
$ hg glog
@ changeset: 1:43d273e49ff1
| tag: tip
| user: Tom Anderson <[email protected]>
| date: Fri May 27 23:44:00 2011 +0100
| summary: continuation
|
o changeset: 0:be2fb6a06ade
user: Tom Anderson <[email protected]>
date: Fri May 27 23:43:45 2011 +0100
summary: the beginning

$ hg update 0
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hostname >second
$ hg add
adding second
$ hg commit -m "that's more like it"
created new head
$ hg glog
@ changeset: 2:0354ae380fea
| tag: tip
| parent: 0:be2fb6a06ade
| user: Tom Anderson <[email protected]>
| date: Fri May 27 23:44:57 2011 +0100
| summary: that's more like it
|
| o changeset: 1:43d273e49ff1
|/ user: Tom Anderson <[email protected]>
| date: Fri May 27 23:44:00 2011 +0100
| summary: continuation
|
o changeset: 0:be2fb6a06ade
user: Tom Anderson <[email protected]>
date: Fri May 27 23:43:45 2011 +0100
summary: the beginning

The punchline is that, as i said, the numbers record the sequence in which
changeset were added to the repository. Changesets 1 and 2 are on
different branches, but they happened in a chronological order, so they
get numbers in that order.

This is a difference from reflog, where the numbers relate to each other,
and you can do arithmetic with them.
Actually, no. It turns out there are two different kinds of tags, and
which one is used depends on this option.

That's the kind of thing that's the reason i don't use git.

tom
 
L

Lawrence D'Oliveiro

It's also the normal way of working in Mercurial (as long as 'resetting'
doesn't mean 'throwing away').

In Git, “resetting†does indeed mean “throwing awayâ€.
Here's a brief session that illustrates what happens:

$ hg update 0

So this command has started a new branch?

In Git, every branch has a name.
That's the kind of thing that's the reason i don't use git.

This is why you need to understand things before trying to rubbish them.
 
J

Joshua Cranmer

So this command has started a new branch?

In Git, every branch has a name.

No, hg update goes to that revision. I think the git equivalent is git
checkout (bizarrely named, if you ask me).

hg branches have names, although branch names are a property of the
changeset and not the repository (which makes git hard for me to use,
having used hg for 6-odd years).
 
L

Lawrence D'Oliveiro

No, hg update goes to that revision.

Yes, but the next commit seemed to spawn off a new branch from there, and I
didn’t see any name attached to it.
I think the git equivalent is git checkout (bizarrely named, if you ask
me).

Why? It gets a snapshot out of the tree. What else would a “checkout†do?
hg branches have names ...

I didn’t see any in the commit example posted earlier.
... although branch names are a property of the changeset and not the
repository (which makes git hard for me to use, having used hg for 6-odd
years).

I’m not sure how that’s different from Git. In Git, a branch head points to
a commit/changeset, and that’s all there is to it.
 
T

Tom Anderson

In Git, “resetting†does indeed mean “throwing awayâ€.

Okay. In that case, the equivalent would actually be a little dance
involving hg clone - Mercurial makes it much harder to throw things away -
and the numbering would be reset, in a manner of speaking, since the clone
would create a new numbering.
So this command has started a new branch?

No, but a branch was created when i committed after that.
In Git, every branch has a name.

Not so in Mercurial. This is, famously, one of the areas of greatest
difference between Git and Mercurial - Mercurial can have completely
anonymous branches, which it seems Git can't, but when it does have named
branches, it brands the name onto each changeset in it, which Git doesn't.
And what Git calls branches, Mercurial calls bookmarks, etc, etc.

AIUI, the reason anonymous branches don't exist in Git is because (a)
there would be no way to get to them (apart from reflog!) and (b) they
would get garbage collected, because names function as the rootset for
garbage collection. Mercurial doesn't do garbage collection (er, i think),
so you can have anonymous branches. The lack of names does obviously mean
that their utility is rather limited in scope.
This is why you need to understand things before trying to rubbish them.

Something i am very happy to say it has never been my policy to do.

tom
 
T

Tom Anderson

Why? It gets a snapshot out of the tree. What else would a “checkoutâ€
do?

Go 'beep' when you wave a packet of cornflakes at it.

'Checkout' and 'checkin' are both poor names, IMO. I appreciate that there
is historical precedent for their use, and so their meanings are well
understood, but as metaphors, they aren't very good. Checking out and
checking in are about controlling exclusive access to something (eg a book
in a library), which is something that some legacy source control systems
do, but not something our shiny modern DVCSs do (or even something CVS dd,
mostly).
I didn’t see any in the commit example posted earlier.

Joshua is talking about named branches. This is an anonymous branch. I
don't know why he's talking about named branches.
I’m not sure how that’s different from Git. In Git, a branch head points
to a commit/changeset, and that’s all there is to it.

Mercurial branches don't point to commits - the branch is a property of
the changeset, it's actually recorded in the changeset's data in the
repository. You could take a changeset, export it, fax it to someone, and
when they imported it and looked at it, it would have the branch name on
it. Some people recoil in horror at this; others love it. It does mean
that Mercurial named branches are not suited for the same uses as Git
branches; in Git, you'd use named branches for developing a few features
locally to send to Linus, but in Mercurial, those would be anonymous
branches, perhaps identified by bookmarks, or stored in separate
repositories. Named branches are more for things like trunk/QA/release.

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,717
Messages
2,569,382
Members
44,704
Latest member
FawnBernay

Latest Threads

Top