[PATCH 1 of 1] ( take 2 ) change tag computation to avoid surprises in case of multiple heads

Georg-W. Koltermann gwk.rko at googlemail.com
Sat Jan 13 05:25:12 CST 2007


Some explanation up front might be in order.

        I first thought the approach of always appending tag lines by
        the "hg tag" command would be the wrong choice.  I thought we
        should rather replace the tag line if the tag was already
        in .hgtags.  But then I found the current choice does have some
        interesting properties.  It allows merging of .hgtags just like
        a normal text file, and it even contains the information that
        some value of a tag was later in history (within the same
        branch) replaced by a newer value, i.e. the tag was updated.
        [I'm using the term "branch" in topological sense here, meaning
        a branch in the history graph.]
        This latter knowledge is extremely valuable.
        
        Really what we want to do when computing tag values currently in
        effect is we only want the very latest state of a tag from each
        head.   All the prior values were replaced later on, and should
        be considered obsolete.  Leading to this rule: "A tag value that
        was replaced by a later line for the same tag in the same file
        is obsolete.  It should be disregarded when computing current
        tag values."

Am Freitag, den 12.01.2007, 13:01 -0600 schrieb Matt Mackall:
> On Sun, Jan 07, 2007 at 07:45:28PM +0100, Georg-W. Koltermann wrote:
> > +            self._obsoletetagvalues = {}
> 
> Is there a reason this needs to be wider than function scope? In other
> words, just do "obsoletetags = {}" please.

The set of obsolete tag values is global.  

Example:

        When we visit the head pertaining to the latest development
        first we might find the following tag value pairs:

                (foo 123abc)
                (foo 456def)
                (foo 789ghi)

        The latest tag value for foo is 789ghi so far, and the other two
        are obsolete.

        Next we might visit a head that branches off of an old version,
        and it might only contain:
        
                (foo 123abc)
        
        If we didn't keep the set of obsolete tag values globally, we
        wouldn't know that this is in fact an obsolete value, and this
        value would replace the desired one (foo 789ghi).

An obsolete tag value from one head could be the last entry
(non-obsolete) in another head.  We need to remember that it was
obsolete in the former head, and hence must keep the obsolete values
globally.

> 
> > +            def parsetag(line, context, tagsmap):
> ...
> > -                self.tagscache[key] = bin_n
> > +                if key in tagsmap:
> > +                    self._obsoletetagvalues[(key, tagsmap[key])] = True
> > +                if not (key, bin_n) in self._obsoletetagvalues:
> > +                    tagsmap[key] = bin_n
> 
> What purpose does tagsmap serve? Why can't we just use tagscache?
> 
> If it's just so that local tags always override .hgtags, simply flush
> the obsoletetags before reading the local tags.
> 

I first did use tagscache, but found it was wrong.

What I want to achieve is to obsolete those tag values that are
superseded by another tag line *in the same file*.  So I need to keep a
memory of tags in the current file only.  tagsmap is per file, tagscache
is global for all files and can't be used.

Looking at the example above, if I used tagscache in place of tagsmap,
then while reading the 2nd head the tag foo would already be found in
tagscache, and the good value 789ghi would be obsoleted.  This is
incorrect.  Obsoletion only occurs within a single tags file (within one
head) not between different ones.



Actually, we could now even detect tag conflicts.  A conflict occurs if
a tag has different values in different heads, and neither of them is
obsoleted in the other head.  Currently I don't care, I simply update
the tagscache from tagsmap so tipmost wins in case of conflict, but this
could be enhanced.   Instead of blindly updating, we could do something
like this:

        for t in tagsmap:
                if t in self.tagscache:
                        #
                        # found a tag that was also in a prior head
                        #
                        if self._obsoletetagvalues[(t
                        self.tagscache[t])]:
                                #
                                # former value is obsolete now, replace
                                it
                                #
                                self.tagscache[t] = tagsmap[t]
                        else:
                                #
                                # neither value is obsolete, signal a
                                conflict
                                #

(I hope I'm correct here, I didn't test this code, and I'm a Python
novice.)

--
Regards,
Georg.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 3441 bytes
Desc: not available
Url : http://www.selenic.com/pipermail/mercurial-devel/attachments/20070113/e952bde8/smime.bin


More information about the Mercurial-devel mailing list