Subject: Re: Git/Mercurial interoperability (and what about bzr?)

From: Theodore Tso <[email-masked]>
Date: Sat, 1 Nov 2008 09:39:31 -0400

On Sat, Nov 01, 2008 at 11:44:21AM +0100, Florian Weimer wrote:
> > Now Mercurial has chosen to use in-tree '.hgtags' file to have global
> > tags transferable.  Never mind the fact that it had to treat this file
> > in special way to have it non-versioned
> 
> Oops, thought this file was versioned.  Things like
> 
>   <http://tycoon.hpl.hp.com/changeset/932:931d181e9f58/.hgtags>

.hgtags is stored as a versioned file in Mercurial.  That's one of the
problems, and it leads to no shortage of headaches.

Some of the problems are discussed here:

   http://www.selenic.com/mercurial/wiki/index.cgi/Tag

Specifically, to quote the Mercurial Wiki:

    The fact that tags identify changesets and are also parts of
    changesets has some potentially confusing implications:

    * The changeset that a tag refers to is always older than the
      changeset that commits the tag itself.

    * Updating a working dir to a particular tag will take that
      directory back to a point before the tag itself existed.

    * Cloning a repo to a particular tag will give you a new repo that
      does not have that tag.

In addition, Mercurial has to play interesting special case games in a
repository which has multiple heads (in git terms, "branches").  When
looking up a tag, it has to take the union of all of the .hgtags files
at the tips of each of the branches.  So if you have a large number of
heads in your Mercurial repository, tags access doesn't scale well at
all.  Mercurial is very much optimized for having a single or at best
a few heads/branches in a repository.

As I mentioned earlier this makes it much more difficult to do a
bidrectional hg/git gateway, since the two DAG's are not toplogically
equivalent, and in fact, *when* you add a tag to a particular
commit/revision can make a distinct difference to the shape of the
DAG.  If you tag right after creating the revision in question, then
there is a tag commit right after the revision.  If you commit a few
dozen changes into the repository, and *then* tag a point many commits
earlier, then the tag commit will be tacked onto the head of whatever
branch you happened to be on.

In fact, in the worst case, if you accidentally tag a revision on the
"maint" branch while you happened to be on the "devel" branch, the tag
for the commit in the "maint" branch will be attached to the "devel"
branch, and while it will work just fine for *you*, someone who only
fetches the "maint" branch might never see the tag that you placed on
the maint branch --- unless they happen to also pull the devel branch.

What fun, eh?

					- Ted