[PATCH 3 of 5] Add option to heads to show only heads for current branch
Eric Hopper
hopper at omnifarious.org
Tue Jun 5 22:12:13 CDT 2007
# HG changeset patch
# User Eric Hopper <hopper at omnifarious.org>
# Date 1181098447 25200
# Node ID 2b43d4e96d9ca28382a182fc90e86b9310453687
# Parent 69f6cc3ee7ac38841e2875986fcb22b74d5d52c3
Add option to heads to show only heads for current branch.
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1253,10 +1253,20 @@ def heads(ui, repo, **opts):
changesets. They are where development generally takes place and
are the usual targets for update and merge operations.
"""
+ branch = None
+ if opts['branch']:
+ branch = repo.dirstate.branch()
+ if branch not in repo.branchtags():
+ ui.warn(_("%s is a new branch that has no heads yet.\n") % (branch,))
+ return 0
if opts['rev']:
- heads = repo.heads(repo.lookup(opts['rev']))
+ heads = repo.heads(repo.lookup(opts['rev']), branch=branch)
else:
- heads = repo.heads()
+ heads = repo.heads(branch=branch)
+ if (branch is not None) and (len(heads) <= 0):
+ ui.warn(_("No changes on branch %s are reachable from revision %s\n") % \
+ (branch, opts['rev']))
+ return 1
displayer = cmdutil.show_changeset(ui, repo, opts)
for n in heads:
displayer.show(changenode=n)
@@ -2822,6 +2832,7 @@ table = {
"heads":
(heads,
[('', 'style', '', _('display using template map file')),
+ ('b', 'branch', None, _("show even inactive heads for just the current branch")),
('r', 'rev', '', _('show only heads which are descendants of rev')),
('', 'template', '', _('display with template'))],
_('hg heads [-r REV]')),
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1079,12 +1079,64 @@ class localrepository(repo.repository):
self.dirstate.update([dest], "a")
self.dirstate.copy(source, dest)
- def heads(self, start=None):
+ def heads(self, start=None, branch=None):
+ if branch is not None:
+ return self.bheads(branch, start)
heads = self.changelog.heads(start)
# sort the output in rev descending order
heads = [(-self.changelog.rev(h), h) for h in heads]
heads.sort()
return [n for (r, n) in heads]
+
+ def bheads(self, branch, start=None):
+ branches = self.branchtags()
+ if branch not in branches:
+ return []
+ # The basic algorithm is this:
+ #
+ # Start from the branch tip since there are no later revisions that can
+ # possibly be in this branch, and the tip is a guaranteed head.
+ #
+ # Remember the tips as the first ancestors, since these by definition
+ # are not heads.
+ #
+ # Step backwards from the brach tip through all the revisions. We are
+ # guaranteed by the rules of Mercurial that we will now be visiting the
+ # nodes in reverse topological order.
+ #
+ # If a revision is one of the ancestors of a head then we can toss it
+ # out of the ancestors list (we've already found it and won't be
+ # visiting it again) and put its parents in the ancestors list.
+ #
+ # Otherwise, if a revision is in the branch it's another head, since it
+ # wasn't in the ancestor list of an existing head. So add it to the
+ # head list, and add its parents to the ancestor list.
+ #
+ # If it is not in the branch ignore it.
+ #
+ # Once we have a list of heads, use nodesbetween to filter out all the
+ # heads that cannot be reached from startrev. There may be a more
+ # efficient way to do this as part of the previous algorithm.
+
+ heads = [self.changelog.rev(branches[branch])]
+ p = self.changelog.parentrevs(heads[0])
+ ancestors = dict.fromkeys(p, 0)
+ del ancestors[nullrev]
+ for rev in xrange(heads[0] - 1, nullrev, -1):
+ if rev in ancestors:
+ p = self.changelog.parentrevs(rev)
+ ancestors.update(dict.fromkeys(p, 0))
+ del ancestors[nullrev]
+ del ancestors[rev]
+ elif self.changectx(rev).branch() == branch:
+ heads.append(rev)
+ p = self.changelog.parentrevs(rev)
+ ancestors.update(dict.fromkeys(p, 0))
+ del ancestors[nullrev]
+ heads = [self.changelog.node(rev) for rev in heads]
+ if start is not None:
+ heads = self.changelog.nodesbetween([start], heads)[2]
+ return heads
def branches(self, nodes):
if not nodes:
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://selenic.com/pipermail/mercurial-devel/attachments/20070605/a0072a28/attachment.pgp
More information about the Mercurial-devel
mailing list