[ANN] tagmerge - an extension for merging .hgtags

Greg Ward greg-hg at gerg.ca
Thu Feb 4 08:30:52 CST 2010


On Thu, Feb 4, 2010 at 12:30 AM, Qi Yang <qi.yang137 at gmail.com> wrote:
> The following is the link to an extension I wrote for merging .hgtags file.

Actually, it's not an extension.  It's a script.

> https://q6yang@bitbucket.org/q6yang/tagmerge/

There are a bunch of code style issues: long lines, trailing
whitespace, etc.  Please run Matt's check-code.py script on your
script.  check-code.py uses the filename to know what checks to apply,
so you need to fool it, e.g.

  ln -s tagmerge tagmerge.py
  ~/src/hg-crew/contrib/check-code.py tagmerge.py

Now to the real stuff:

> def readtags(filename):
>    '''parsing .hgtags file'''
>     tags = {}
>     with open(filename) as f:
>          for line in f.readlines():
>              tagid, tagname = line.split(" ")
>              tags[tagname.strip()] = tagid
>     return tags

That won't work.  You cannot simply store .hgtags in a dictionary.
Tag names can be repeated and order matters.  Play around with
deleting and moving tags to see how that works:

  hg tag -r 5 foo
  hg tag -f -r 7 foo
  hg tag --remove foo
  hg tag -r 4 foo

The resulting .hgtags looks very strange... until you think about what
happens when you merge two .hgtags that have had similar games played.

If it's any consolation, I made the exact same mistake around a year
ago, when I posted my naive attempt at a tag-merging script.  Since
then, Matt cunningly tricked me into becoming an .hgtags expert, so
now I get to handle these sorts of things.  ;-)

See mercurial/tags.py for code that understands how to read tags.  You
probably want to reuse _readtags().

IMHO this is something that should be improved in core Mercurial.  I
think your ultimate goal should be a patch to mercurial/tags.py with
all the tricky tag-merging logic, and then a front-end script in
contrib/.  For now, keeping things in a little standalone script is
probably the right thing to do.  Once that works it should be clear
what belongs in tags.py.

Another comment:

> def pickmergetool(ui):
>     '''pick merge tool for merging conflict: pick the highest priority one
> or use simple merge if there are no other merge tools'''
>     tools = {}
>     for k,v in ui.configitems("merge-tools"):
>         toolname = k.split('.')[0]
>         if toolname not in tools:
>             tools[toolname] = int(_toolstr(ui, toolname, "priority", "0"))
>     if len(tools) == 0 or toolname == 'tagmerge':
>         ui.debug("simplemerge will be used\n")
>         return None
>     tools = sorted([(-p,t) for t,p in tools.items()])
>     priority, pickedtool = tools[0]
>     ui.debug("Pick merge-tool %s" % (pickedtool))

Isn't this logic already implemented somewhere in core Mercurial?  If
it's not available to you in a reusable form, please submit a
refactoring patch to correct that.

> def writenewtags(filename, newtags):
>     '''write non-local tags to the local .hgtags file'''
>     with open(filename, 'r+') as f:
>         for line in f.readlines():
>             tagid, tagname = line.split(" ")
>             for itemtagname, itemtagid in newtags.items():
>                 if tagid == itemtagid and tagname != itemtagname:
>                     f.write(itemtagid + ' ' + itemtagname)
>                     break
>         f.write('\n')

And this is buried deep in localrepo.py.  It should probably be
factored out to tags.py for reusability.  Please submit another
refactoring patch for that!

Thanks!

Greg


More information about the Mercurial-devel mailing list