--- a/mercurial/commands.py Wed Mar 14 01:26:09 2007 -0500
+++ b/mercurial/commands.py Wed Mar 14 19:17:40 2007 -0500
@@ -2445,14 +2445,20 @@
"please use 'hg tag [-r REV] NAME' instead\n"))
if opts['rev']:
raise util.Abort(_("use only one form to specify the revision"))
+ if opts['rev'] and opts['remove']:
+ raise util.Abort(_("--rev and --remove are incompatible"))
if opts['rev']:
rev_ = opts['rev']
+ message = opts['message']
+ if opts['remove']:
+ rev_ = nullid
+ if not message:
+ message = _('Removed tag %s') % name
if not rev_ and repo.dirstate.parents()[1] != nullid:
raise util.Abort(_('uncommitted merge - please provide a '
'specific revision'))
r = repo.changectx(rev_).node()
- message = opts['message']
if not message:
message = _('Added tag %s for changeset %s') % (name, short(r))
@@ -2913,7 +2919,8 @@
('m', 'message', '', _('message for tag commit log entry')),
('d', 'date', '', _('record datecode as commit date')),
('u', 'user', '', _('record user as commiter')),
- ('r', 'rev', '', _('revision to tag'))],
+ ('r', 'rev', '', _('revision to tag')),
+ ('', 'remove', None, _('remove a tag'))],
_('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
"tags": (tags, [], _('hg tags')),
"tip":
--- a/mercurial/localrepo.py Wed Mar 14 01:26:09 2007 -0500
+++ b/mercurial/localrepo.py Wed Mar 14 19:17:40 2007 -0500
@@ -278,55 +278,80 @@
def tags(self):
'''return a mapping of tag to node'''
- if not self.tagscache:
- self.tagscache = {}
+ if self.tagscache:
+ return self.tagscache
+
+ globaltags = {}
- def parsetag(line, context):
- if not line:
- return
+ def readtags(lines, fn):
+ filetags = {}
+ count = 0
+
+ def warn(msg):
+ self.ui.warn(_("%s, line %s: %s\n") % (fn, count, msg))
+
+ for l in lines:
+ count += 1
+ if not l:
+ continue
s = l.split(" ", 1)
if len(s) != 2:
- self.ui.warn(_("%s: cannot parse entry\n") % context)
- return
+ warn(_("cannot parse entry"))
+ continue
node, key = s
key = util.tolocal(key.strip()) # stored in UTF-8
try:
bin_n = bin(node)
except TypeError:
- self.ui.warn(_("%s: node '%s' is not well formed\n") %
- (context, node))
- return
+ warn(_("node '%s' is not well formed") % node)
+ continue
if bin_n not in self.changelog.nodemap:
- self.ui.warn(_("%s: tag '%s' refers to unknown node\n") %
- (context, key))
- return
- self.tagscache[key] = bin_n
+ warn(_("tag '%s' refers to unknown node") % key)
+ continue
+
+ h = {}
+ if key in filetags:
+ n, h = filetags[key]
+ h[n] = True
+ filetags[key] = (bin_n, h)
- # read the tags file from each head, ending with the tip,
- # and add each tag found to the map, with "newer" ones
- # taking precedence
- f = None
- for rev, node, fnode in self._hgtagsnodes():
- f = (f and f.filectx(fnode) or
- self.filectx('.hgtags', fileid=fnode))
- count = 0
- for l in f.data().splitlines():
- count += 1
- parsetag(l, _("%s, line %d") % (str(f), count))
+ for k,nh in filetags.items():
+ if k not in globaltags:
+ globaltags[k] = nh
+ continue
+ # we prefer the global tag if:
+ # it supercedes us OR
+ # mutual supercedes and it has a higher rank
+ # otherwise we win because we're tip-most
+ an, ah = nh
+ bn, bh = globaltags[k]
+ if bn != an and an in bh and \
+ (bn not in ah or len(bh) > len(ah)):
+ an = bn
+ ah.update(bh)
+ globaltags[k] = an, ah
- try:
- f = self.opener("localtags")
- count = 0
- for l in f:
- # localtags are stored in the local character set
- # while the internal tag table is stored in UTF-8
- l = util.fromlocal(l)
- count += 1
- parsetag(l, _("localtags, line %d") % count)
- except IOError:
- pass
+ # read the tags file from each head, ending with the tip
+ f = None
+ for rev, node, fnode in self._hgtagsnodes():
+ f = (f and f.filectx(fnode) or
+ self.filectx('.hgtags', fileid=fnode))
+ readtags(f.data().splitlines(), f)
- self.tagscache['tip'] = self.changelog.tip()
+ try:
+ data = util.fromlocal(self.opener("localtags").read())
+ # localtags are stored in the local character set
+ # while the internal tag table is stored in UTF-8
+ readtags(data.splitlines(), "localtags")
+ except IOError:
+ pass
+
+ self.tagscache = {}
+ for k,nh in globaltags.items():
+ n = nh[0]
+ if n != nullid:
+ self.tagscache[k] = n
+ self.tagscache['tip'] = self.changelog.tip()
return self.tagscache
--- a/tests/test-tags Wed Mar 14 01:26:09 2007 -0500
+++ b/tests/test-tags Wed Mar 14 19:17:40 2007 -0500
@@ -63,7 +63,7 @@
hg tags
hg tip
-# tags from later heads override previous ones
+# test tag precedence rules
cd ..
hg init t2
cd t2
@@ -79,3 +79,7 @@
echo >> foo
hg ci -m 'change foo 2' -d '1000000 0' # rev 4
hg tags
+
+hg tag --remove -d '1000000 0' bar
+hg tip
+hg tags
--- a/tests/test-tags.out Wed Mar 14 01:26:09 2007 -0500
+++ b/tests/test-tags.out Wed Mar 14 19:17:40 2007 -0500
@@ -41,4 +41,11 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
tip 4:36195b728445
-bar 0:b409d9da318e
+bar 1:b204a97e6e8d
+changeset: 5:57e1983b4a60
+tag: tip
+user: test
+date: Mon Jan 12 13:46:40 1970 +0000
+summary: Removed tag bar
+
+tip 5:57e1983b4a60