Counterintuitive tag behaviour (broken design?)

Johan Herland johherla at online.no
Tue Mar 13 10:23:06 CDT 2007


Hi,
I've been using Mercurial for a little while, and so far I really like it a 
lot. However, in the last couple of days, I've started experimenting with 
tags, and what I found was first puzzling, and after some more 
experimentation my feeling can be best described as disbelief. Now, this may 
be a big misunderstanding on my part as to how tags behave in Mercurial, but 
I'd like to run this by you anyway.

Consider the following scenario (similar scenarios have been discussed before 
on this mailing list according to the archives):

<command-line session>
$ hg init
$ touch a
$ hg add a
$ hg commit -m"Added a."
$ echo "foo" > a
$ hg commit -m"foo -> a."
$ hg tag baz
$ hg up 0
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ echo "bar" > a
$ hg commit -m"bar -> a."
$ hg tag baz
$ hg heads
changeset:   4:9f14afcf590f
tag:         tip
summary:     Added tag baz for changeset e0c70b2c94aa

changeset:   2:eb6ad0bee830
summary:     Added tag baz for changeset 27dbcef48adb
$ hg tags
tip                                4:9f14afcf590f
baz                                3:e0c70b2c94aa
$ hg up -C 2
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg tags
tip                                4:9f14afcf590f
baz                                3:e0c70b2c94aa
</command-line session>

So far, everything is ok. The latter tag command in rev.4 overrides the one in 
rev.2 [1], and this is the case no matter which of the two branches I'm 
currently on.

Now, consider I make some totally unrelated changes to the first branch:
<command-line session>
$ hg id
eb6ad0bee830 (i.e. rev.2)
$ echo "spam" >> a
$ hg commit -m"spam -> a."
$ hg heads
changeset:   5:f0a5156412fb
tag:         tip
parent:      2:eb6ad0bee830
summary:     spam -> a.

changeset:   4:9f14afcf590f
summary:     Added tag baz for changeset e0c70b2c94aa
$ hg tags
tip                                5:f0a5156412fb
baz                                1:27dbcef48adb
$ hg up -C 4
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg tags
tip                                5:f0a5156412fb
baz                                1:27dbcef48adb
</command-line session>

As you can see, by performing an unrelated commit on the first branch, 
the "baz" tag has changed on BOTH branches. I cannot in any way see WHY an 
unrelated commit should change the meaning of a tag, much less change the 
meaning of a tag on an entirely unrelated branch.

Now, after reading some discussions on the mailing list and in the bug 
tracker, I think I understand _what_ Mercurial does in this situation [2], 
but I cannot at all believe that what I'm seeing is (A) intuitive, and (B) 
has been consciously designed/decided to be the intended result. To me, it 
seems more like an unintended consequence/side-effect of the way tags 
currently work in Mercurial.

After thinking about this issue for a while, I'm starting to question the way 
tags are designed in Mercurial. Although I'm very sympathetic to the basic 
idea of revision controlling tags, I have a hard time seeing that the idea is 
successfully implemented in Mercurial. Even though the .hgtags file itself is 
revision controlled, the lookup/resolving of tag names goes across all 
branches/heads with preference to some arbitrary measure (tipmost-ness), and 
thus seems to break the integrity of the revision control system (e.g. by 
resulting in consequences as seen above).

If someone could please enlighten me as to what I don't get about the current 
design, and why the current behaviour is desirable, I would be most 
grateful. Otherwise, if the current behaviour is in fact not desirable, it 
would be interesting to discuss how the behaviour can be revised in time for 
the 1.0 release.


Have fun!

...Johan


[1]: Well, not entirely ok... I'd very much like for "hg tag" to refuse to 
move an existing tag without being given a "--force" argument (cf. CVS, git, 
and most other rev.control systems, I guess).

[2]: Mercurial resolves tag names by looking them up on all repository heads, 
with a preference towards the tipmost tag definitions. When resolving 
the "baz" tag name, the tag definition made in rev.2 is suddenly closer to 
the tip than the one in rev.4, because of the (unrelated) commit in rev.5.

-- 
Johan Herland, <johherla at online.no>
www.herland.net


More information about the Mercurial mailing list