[PATCH 4 of 6] Add option to heads to show only heads for current branch

Eric Hopper hopper at omnifarious.org
Thu Jun 7 17:58:19 CDT 2007


# HG changeset patch
# User Eric Hopper <hopper at omnifarious.org>
# Date 1181256556 25200
# Node ID 8fe2e9aaed51002c4d4746a3664d23feb74d1044
# Parent  7f10f536f11273b87721bf9e6ce83018f179ed50
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
@@ -1082,12 +1082,60 @@ 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.
+
+        set = util.hgset
+        heads = [self.changelog.rev(branches[branch])]
+        # Don't care if ancestors contains nullrev or not.
+        ancestors = set(self.changelog.parentrevs(heads[0]))
+        for rev in xrange(heads[0] - 1, nullrev, -1):
+            if rev in ancestors:
+                ancestors.update(self.changelog.parentrevs(rev))
+                ancestors.remove(rev)
+            elif self.changectx(rev).branch() == branch:
+                heads.append(rev)
+                ancestors.update(self.changelog.parentrevs(rev))
+        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/20070607/41d46d57/attachment.pgp 


More information about the Mercurial-devel mailing list