diff mercurial/revset.py @ 29348:2188f170f5b6

revset: add new topographical sort Sort revisions in reverse revision order but grouped by topographical branches. Visualised as a graph, instead of: o 4 | | o 3 | | | o 2 | | o | 1 |/ o 0 revisions on a 'main' branch are emitted before 'side' branches: o 4 | o 1 | | o 3 | | | o 2 |/ o 0 where what constitutes a 'main' branch is configurable, so the sort could also result in: o 3 | o 2 | | o 4 | | | o 1 |/ o 0 This sort was already available as an experimental option in the graphmod module, from which it is now removed. This sort is best used with hg log -G: $ hg log -G "sort(all(), topo)"
author Martijn Pieters <mjpieters@fb.com>
date Mon, 13 Jun 2016 18:20:00 +0100
parents 98535ad46fc0
children ec75d77df9d7
line wrap: on
line diff
--- a/mercurial/revset.py	Mon Jun 13 18:20:00 2016 +0100
+++ b/mercurial/revset.py	Mon Jun 13 18:20:00 2016 +0100
@@ -1843,7 +1843,7 @@
     'date': lambda c: c.date()[0],
 }
 
-@predicate('sort(set[, [-]key...])', safe=True)
+@predicate('sort(set[, [-]key... [, ...]])', safe=True)
 def sort(repo, subset, x):
     """Sort set by keys. The default sort order is ascending, specify a key
     as ``-key`` to sort in descending order.
@@ -1855,8 +1855,14 @@
     - ``desc`` for the commit message (description),
     - ``user`` for user name (``author`` can be used as an alias),
     - ``date`` for the commit date
+    - ``topo`` for a reverse topographical sort
+
+    The ``topo`` sort order cannot be combined with other sort keys. This sort
+    takes one optional argument, ``topo.firstbranch``, which takes a revset that
+    specifies what topographical branches to prioritize in the sort.
+
     """
-    args = getargsdict(x, 'sort', 'set keys')
+    args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
     if 'set' not in args:
         # i18n: "sort" is a keyword
         raise error.ParseError(_('sort requires one or two arguments'))
@@ -1868,12 +1874,35 @@
     s = args['set']
     keys = keys.split()
     revs = getset(repo, subset, s)
+
+    if len(keys) > 1 and any(k.lstrip('-') == 'topo' for k in keys):
+        # i18n: "topo" is a keyword
+        raise error.ParseError(_(
+            'topo sort order cannot be combined with other sort keys'))
+
+    firstbranch = ()
+    if 'topo.firstbranch' in args:
+        if any(k.lstrip('-') == 'topo' for k in keys):
+            firstbranch = getset(repo, subset, args['topo.firstbranch'])
+        else:
+            # i18n: "topo" and "topo.firstbranch" are keywords
+            raise error.ParseError(_(
+                'topo.firstbranch can only be used when using the topo sort '
+                'key'))
+
     if keys == ["rev"]:
         revs.sort()
         return revs
     elif keys == ["-rev"]:
         revs.sort(reverse=True)
         return revs
+    elif keys[0] in ("topo", "-topo"):
+        revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
+                       istopo=True)
+        if keys[0][0] == '-':
+            revs.reverse()
+        return revs
+
     # sort() is guaranteed to be stable
     ctxs = [repo[r] for r in revs]
     for k in reversed(keys):
@@ -1887,7 +1916,7 @@
             raise error.ParseError(_("unknown sort key %r") % fk)
     return baseset([c.rev() for c in ctxs])
 
-def groupbranchiter(revs, parentsfunc, firstbranch=()):
+def _toposort(revs, parentsfunc, firstbranch=()):
     """Yield revisions from heads to roots one (topo) branch at a time.
 
     This function aims to be used by a graph generator that wishes to minimize