changeset 2533:7abea6ea172c mercurial-3.9

test-compat: merge with mercurial-4.0 branch The new 'olog' command is not working with 3.9 so we skill all mentions of it in the tests. This also apply to the topic extensions.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 31 May 2017 14:28:14 +0200
parents 8fadd87da07e (current diff) ca157d06b2dc (diff)
children b3dac812fb2a 22c05418ca71
files hgext3rd/evolve/templatekw.py tests/test-discovery-obshashrange.t tests/test-evolve-cycles.t tests/test-evolve-effectflags.t tests/test-evolve-obshistory-complex.t tests/test-evolve.t tests/test-metaedit.t
diffstat 33 files changed, 2591 insertions(+), 1006 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon May 22 15:42:13 2017 +0200
+++ b/.hgtags	Wed May 31 14:28:14 2017 +0200
@@ -50,3 +50,4 @@
 5ef112a6eb875633a7925cde61b7d2d9e65b3a56 6.0.1
 8510d3fd7c3b312dc731f4c29badc415d504558a 6.1.0
 d4ee0274a8efbaf3d73a659998248c379c61c2bf 6.2.0
+0af99106b0754426913b5c82fb52dc70d4d299f6 6.2.1
--- a/README	Mon May 22 15:42:13 2017 +0200
+++ b/README	Wed May 31 14:28:14 2017 +0200
@@ -112,7 +112,32 @@
 Changelog
 =========
 
-6.2.1 - in progress
+6.3.0 - in progress
+-------------------
+
+ - olog: add an 'obslog' alias
+ - olog: add an '--all' option to show the whole obsolescence history tree.
+ - evolution: add an experiment to track the effect of rewrites.
+   (See hg help - evolve for details)
+ - exchange: fix the "relevant-markers" algorithm to include inline prune.
+   This will impact discovery of obsmarkers between server and client if one
+   still uses the old algorithm. Please upgrade both clients and servers as
+   soon as possible.
+   (See changeset 176d1a0ce385 in core Mercurial for details)
+ - obsdiscovery: add a config flag to disable all obsmarkers discovery
+   (See hg help - evolve for details)
+ - template: add a 'precursors' template that display the closests precursors of changesets
+ - template: add a 'successors' template that display the closests successors of changesets
+ - template: add a 'obsfate' template that display how a changeset has evolved
+ - new discovery experiment: add options to restrict memory consumption on
+   large repository (see "hg help -e evolve" for details).
+
+6.2.2 - in progress
+-------------------
+
+  * evolve: fix --rev handling in --list mode
+
+6.2.1 -- 2017-05-23
 -------------------
 
  - prune: fix a crash related to color handling,
--- a/debian/changelog	Mon May 22 15:42:13 2017 +0200
+++ b/debian/changelog	Wed May 31 14:28:14 2017 +0200
@@ -1,3 +1,9 @@
+mercurial-evolve (6.2.1-1) unstable; urgency=medium
+
+  * new upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@ens-lyon.org>  Tue, 23 May 2017 10:47:36 +0200
+
 mercurial-evolve (6.2.0-1) unstable; urgency=medium
 
   * new upstream release
--- a/hgext3rd/evolve/__init__.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/__init__.py	Wed May 31 14:28:14 2017 +0200
@@ -44,6 +44,12 @@
     # * abort: abort the push
     auto-publish = ignore
 
+    # For some large repository with few markers, the current  for obsolescence
+    # markers discovery can get in the way. You can disable it with the
+    # configuration option below. This means all pushes and pulls will
+    # re-exchange all markers every time.
+    evolution.obsdiscovery = yes
+
 Obsolescence Markers Discovery Experiment
 =========================================
 
@@ -70,6 +76,37 @@
   # (recommended 'off' for developer repositories)
   # (recommended 'yes' for server (default))
   obshashrange.warm-cache = no
+
+It is recommended to enable the blackbox extension to gather useful
+data about the experiment. It is shipped with Mercurial so no extra
+install needed.
+
+    [extensions]
+    blackbox =
+
+Finally some extra option are available to help tame the experimental
+implementation of some of the algorithms:
+
+    [experimental]
+    # restrict cache size to reduce memory consumption
+    obshashrange.lru-size = 2000 # default is 2000
+
+Effect Flag Experiment
+======================
+
+We are experimenting with a way to register what changed between a precursor
+and its successors (content, description, parent, etc...). For example, having
+this information is helpful to show what changed between an obsolete changeset
+and its tipmost successors.
+
+The following config control the experiment::
+
+  [experimental]
+  # activate the registration of effect flags in obs markers
+  evolution.effect-flags = yes
+
+The effect flags are shown in the obglog command output without particular
+configuration of you want to inspect them.
 """
 
 evolutionhelptext = """
@@ -153,12 +190,11 @@
     lock as lockmod,
     merge,
     node,
+    obsolete,
     patch,
     phases,
     revset,
     scmutil,
-    templatekw,
-    obsolete
 )
 
 from mercurial.commands import walkopts, commitopts, commitopts2, mergetoolopts
@@ -167,14 +203,16 @@
 
 from . import (
     checkheads,
+    compat,
     debugcmd,
     exthelper,
     metadata,
     obscache,
     obsexchange,
+    obshistory,
     safeguard,
+    templatekw,
     utility,
-    obshistory
 )
 
 __version__ = metadata.__version__
@@ -217,6 +255,8 @@
 eh.merge(safeguard.eh)
 eh.merge(obscache.eh)
 eh.merge(obshistory.eh)
+eh.merge(templatekw.eh)
+eh.merge(compat.eh)
 uisetup = eh.final_uisetup
 extsetup = eh.final_extsetup
 reposetup = eh.final_reposetup
@@ -508,29 +548,6 @@
     s.sort()
     return subset & s
 
-### template keywords
-# XXX it does not handle troubles well :-/
-
-@eh.templatekw('obsolete')
-def obsoletekw(repo, ctx, templ, **args):
-    """:obsolete: String. Whether the changeset is ``obsolete``.
-    """
-    if ctx.obsolete():
-        return 'obsolete'
-    return ''
-
-@eh.templatekw('troubles')
-def showtroubles(**args):
-    """:troubles: List of strings. Evolution troubles affecting the changeset
-    (zero or more of "unstable", "divergent" or "bumped")."""
-    ctx = args['ctx']
-    try:
-        # specify plural= explicitly to trigger TypeError on hg < 4.2
-        return templatekw.showlist('trouble', ctx.troubles(), args,
-                                   plural='troubles')
-    except TypeError:
-        return templatekw.showlist('trouble', ctx.troubles(), plural='troubles',
-                                   **args)
 
 #####################################################################
 ### Various trouble warning                                       ###
@@ -538,29 +555,6 @@
 
 # This section take care of issue warning to the user when troubles appear
 
-
-def _getobsoletereason(repo, revnode):
-    """ Return a tuple containing:
-    - the reason a revision is obsolete (diverged, pruned or superseed)
-    - the list of successors short node if the revision is neither pruned
-    or has diverged
-    """
-    successorssets = obsolete.successorssets(repo, revnode)
-
-    if len(successorssets) == 0:
-        # The commit has been pruned
-        return ('pruned', [])
-    elif len(successorssets) > 1:
-        return ('diverged', [])
-    else:
-        # No divergence, only one set of successors
-        successors = [node.short(node_id) for node_id in successorssets[0]]
-
-        if len(successors) == 1:
-            return ('superseed', successors)
-        else:
-            return ('superseed_split', successors)
-
 def _warnobsoletewc(ui, repo):
     rev = repo['.']
 
@@ -577,7 +571,7 @@
         return
 
     # Show a warning for helping the user to solve the issue
-    reason, successors = _getobsoletereason(repo, rev.node())
+    reason, successors = obshistory._getobsfateandsuccs(repo, rev.node())
 
     if reason == 'pruned':
         solvemsg = _("use 'hg evolve' to update to its parent successor")
@@ -615,7 +609,7 @@
 
             unfilteredrepo = repo.unfiltered()
             rev = unfilteredrepo[changeid]
-            reason, successors = _getobsoletereason(unfilteredrepo, rev.node())
+            reason, successors = obshistory._getobsfateandsuccs(unfilteredrepo, rev.node())
 
             # Be more precise in cqse the revision is superseed
             if reason == 'superseed':
@@ -810,7 +804,10 @@
             message = old.description()
 
         user = commitopts.get('user') or old.user()
-        date = commitopts.get('date') or None # old.date()
+        # TODO: In case not date is given, we should take the old commit date
+        # if we are working one one changeset or mimic the fold behavior about
+        # date
+        date = commitopts.get('date') or None
         extra = dict(commitopts.get('extra', old.extra()))
         extra['branch'] = head.branch()
 
@@ -1310,7 +1307,7 @@
 
     revs = repo.revs('+'.join("%s()" % t for t in troublecategories))
     if opts.get('rev'):
-        revs = revs & repo.revs(opts.get('rev'))
+        revs = scmutil.revrange(repo, opts.get('rev'))
 
     fm = ui.formatter('evolvelist', opts)
     for rev in revs:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/compat.py	Wed May 31 14:28:14 2017 +0200
@@ -0,0 +1,57 @@
+# Copyright 2017 Octobus <contact@octobus.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""
+Compatibility module
+"""
+
+from mercurial import (
+    hg,
+    obsolete
+)
+
+from . import (
+    exthelper,
+)
+
+eh = exthelper.exthelper()
+
+if not hasattr(hg, '_copycache'):
+    # exact copy of relevantmarkers as in Mercurial-176d1a0ce385
+    # this fixes relevant markers computation for version < hg-4.3
+    @eh.wrapfunction(obsolete.obsstore, 'relevantmarkers')
+    def relevantmarkers(orig, self, nodes):
+        """return a set of all obsolescence markers relevant to a set of nodes.
+
+        "relevant" to a set of nodes mean:
+
+        - marker that use this changeset as successor
+        - prune marker of direct children on this changeset
+        - recursive application of the two rules on precursors of these markers
+
+        It is a set so you cannot rely on order.
+
+        Backport of mercurial changeset 176d1a0ce385 for version < 4.3
+        """
+
+        pendingnodes = set(nodes)
+        seenmarkers = set()
+        seennodes = set(pendingnodes)
+        precursorsmarkers = self.precursors
+        succsmarkers = self.successors
+        children = self.children
+        while pendingnodes:
+            direct = set()
+            for current in pendingnodes:
+                direct.update(precursorsmarkers.get(current, ()))
+                pruned = [m for m in children.get(current, ()) if not m[1]]
+                direct.update(pruned)
+                pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
+                direct.update(pruned)
+            direct -= seenmarkers
+            pendingnodes = set([m[0] for m in direct])
+            seenmarkers |= direct
+            pendingnodes -= seennodes
+            seennodes |= pendingnodes
+        return seenmarkers
--- a/hgext3rd/evolve/debugcmd.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/debugcmd.py	Wed May 31 14:28:14 2017 +0200
@@ -10,7 +10,10 @@
 #  * We could have the same code in core as `hg debugobsolete --stat`,
 #  * We probably want a way for the extension to hook in for extra data.
 
-from mercurial import node
+from mercurial import (
+    obsolete,
+    node,
+)
 
 from mercurial.i18n import _
 
@@ -41,7 +44,8 @@
     store = repo.obsstore
     unfi = repo.unfiltered()
     nm = unfi.changelog.nodemap
-    ui.write(_('markers total:              %9i\n') % len(store._all))
+    nbmarkers = len(store._all)
+    ui.write(_('markers total:              %9i\n') % nbmarkers)
     sucscount = [0, 0, 0, 0]
     known = 0
     parentsdata = 0
@@ -51,6 +55,8 @@
     clustersmap = {}
     # same data using parent information
     pclustersmap = {}
+    size_v0 = []
+    size_v1 = []
     for mark in store:
         if mark[0] in nm:
             known += 1
@@ -72,6 +78,8 @@
         # same with parent data
         nodes.update(parents)
         _updateclustermap(nodes, mark, pclustersmap)
+        size_v0.append(len(obsolete._fm0encodeonemarker(mark)))
+        size_v1.append(len(obsolete._fm1encodeonemarker(mark)))
 
     # freezing the result
     for c in clustersmap.values():
@@ -95,6 +103,27 @@
     for key in sorted(metakeys):
         ui.write(('    %15s:        %9i\n' % (key, metakeys[key])))
 
+    size_v0.sort()
+    size_v1.sort()
+    if size_v0:
+        ui.write('marker size:\n')
+        # format v1
+        ui.write('    format v1:\n')
+        ui.write(('        smallest length:    %9i\n' % size_v1[0]))
+        ui.write(('        longer length:      %9i\n' % size_v1[-1]))
+        median = size_v1[nbmarkers // 2]
+        ui.write(('        median length:      %9i\n' % median))
+        mean = sum(size_v1) // nbmarkers
+        ui.write(('        mean length:        %9i\n' % mean))
+        # format v0
+        ui.write('    format v0:\n')
+        ui.write(('        smallest length:    %9i\n' % size_v0[0]))
+        ui.write(('        longer length:      %9i\n' % size_v0[-1]))
+        median = size_v0[nbmarkers // 2]
+        ui.write(('        median length:      %9i\n' % median))
+        mean = sum(size_v0) // nbmarkers
+        ui.write(('        mean length:        %9i\n' % mean))
+
     allclusters = list(set(clustersmap.values()))
     allclusters.sort(key=lambda x: len(x[1]))
     ui.write(('disconnected clusters:      %9i\n' % len(allclusters)))
--- a/hgext3rd/evolve/metadata.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/metadata.py	Wed May 31 14:28:14 2017 +0200
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-__version__ = '6.2.1.dev'
+__version__ = '6.3.0.dev'
 testedwith = '3.8.4 3.9.2 4.0.2 4.1.2 4.2'
 minimumhgversion = '3.8'
 buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obsdiscovery.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/obsdiscovery.py	Wed May 31 14:28:14 2017 +0200
@@ -72,97 +72,6 @@
 eh.merge(stablerange.eh)
 obsexcmsg = utility.obsexcmsg
 
-##########################################
-###  trigger discovery during exchange ###
-##########################################
-
-@eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
-def _pushdiscoveryobsmarkers(orig, pushop):
-    if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
-        and pushop.repo.obsstore
-        and 'obsolete' in pushop.remote.listkeys('namespaces')):
-        repo = pushop.repo
-        obsexcmsg(repo.ui, "computing relevant nodes\n")
-        revs = list(repo.revs('::%ln', pushop.futureheads))
-        unfi = repo.unfiltered()
-        cl = unfi.changelog
-        if not pushop.remote.capable('_evoext_obshash_0'):
-            # do not trust core yet
-            # return orig(pushop)
-            nodes = [cl.node(r) for r in revs]
-            if nodes:
-                obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
-                                   % len(nodes))
-                pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
-            else:
-                obsexcmsg(repo.ui, "markers already in sync\n")
-                pushop.outobsmarkers = []
-                pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
-            return
-
-        common = []
-        missing = None
-        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
-                           % len(revs))
-        commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
-        if _canobshashrange(repo, pushop.remote):
-            missing = findmissingrange(pushop.ui, unfi, pushop.remote,
-                                       commonrevs)
-        else:
-            common = findcommonobsmarkers(pushop.ui, unfi, pushop.remote,
-                                          commonrevs)
-        if missing is None:
-            revs = list(unfi.revs('%ld - (::%ln)', revs, common))
-            nodes = [cl.node(r) for r in revs]
-        else:
-            revs = list(repo.revs('only(%ln, %ln)', pushop.futureheads,
-                        pushop.outgoing.commonheads))
-            nodes = [cl.node(r) for r in revs]
-            nodes += missing
-
-        if nodes:
-            obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
-                               % len(nodes))
-            pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
-        else:
-            obsexcmsg(repo.ui, "markers already in sync\n")
-            pushop.outobsmarkers = []
-
-@eh.extsetup
-def _installobsmarkersdiscovery(ui):
-    olddisco = exchange.pushdiscoverymapping['obsmarker']
-
-    def newdisco(pushop):
-        _pushdiscoveryobsmarkers(olddisco, pushop)
-    exchange.pushdiscoverymapping['obsmarker'] = newdisco
-
-def buildpullobsmarkersboundaries(pullop, bundle2=True):
-    """small function returning the argument for pull markers call
-    may to contains 'heads' and 'common'. skip the key for None.
-
-    It is a separed function to play around with strategy for that."""
-    repo = pullop.repo
-    remote = pullop.remote
-    unfi = repo.unfiltered()
-    revs = unfi.revs('::(%ln - null)', pullop.common)
-    boundaries = {'heads': pullop.pulledsubset}
-    if not revs: # nothing common
-        boundaries['common'] = [node.nullid]
-        return boundaries
-
-    if bundle2 and _canobshashrange(repo, remote):
-        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
-                  % len(revs))
-        boundaries['missing'] = findmissingrange(repo.ui, repo, pullop.remote,
-                                                 revs)
-    elif remote.capable('_evoext_obshash_0'):
-        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
-                           % len(revs))
-        boundaries['common'] = findcommonobsmarkers(repo.ui, repo, remote, revs)
-    else:
-        boundaries['common'] = [node.nullid]
-    return boundaries
-
 ##################################
 ###  Code performing discovery ###
 ##################################
@@ -439,7 +348,7 @@
 
 class _obshashcache(obscache.dualsourcecache):
 
-    _schemaversion = 1
+    _schemaversion = 2
 
     _cachename = 'evo-ext-obshashrange' # used for error message
 
@@ -794,6 +703,9 @@
 # the obshash of its parents.  This is similar to what happend for changeset
 # node where the parent is used in the computation
 
+def _canobshashtree(repo, remote):
+    return remote.capable('_evoext_obshash_0')
+
 @eh.command(
     'debugobsrelsethashtree',
     [('', 'v0', None, 'hash on marker format "0"'),
@@ -925,3 +837,126 @@
     def newcap(repo, proto):
         return _obshash_capabilities(oldcap, repo, proto)
     wireproto.commands['capabilities'] = (newcap, args)
+
+##########################################
+###  trigger discovery during exchange ###
+##########################################
+
+def _dopushmarkers(pushop):
+    return (# we have any markers to push
+            pushop.repo.obsstore
+            # exchange of obsmarkers is enabled locally
+            and obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
+            # remote server accept markers
+            and 'obsolete' in pushop.remote.listkeys('namespaces'))
+
+def _pushobshashrange(pushop, commonrevs):
+    repo = pushop.repo.unfiltered()
+    remote = pushop.remote
+    missing = findmissingrange(pushop.ui, repo, remote, commonrevs)
+    missing += pushop.outgoing.missing
+    return missing
+
+def _pushobshashtree(pushop, commonrevs):
+    repo = pushop.repo.unfiltered()
+    remote = pushop.remote
+    node = repo.changelog.node
+    common = findcommonobsmarkers(pushop.ui, repo, remote, commonrevs)
+    revs = list(repo.revs('only(%ln, %ln)', pushop.futureheads, common))
+    return [node(r) for r in revs]
+
+# available discovery method, first valid is used
+# tuple (canuse, perform discovery))
+obsdiscoveries = [
+    (_canobshashrange, _pushobshashrange),
+    (_canobshashtree, _pushobshashtree),
+]
+
+obsdiscovery_skip_message = """\
+(skipping discovery of obsolescence markers, will exchange everything)
+(controled by 'experimental.evolution.obsdiscovery' configuration)
+"""
+
+def usediscovery(repo):
+    return repo.ui.configbool('experimental', 'evolution.obsdiscovery', True)
+
+@eh.wrapfunction(exchange, '_pushdiscoveryobsmarkers')
+def _pushdiscoveryobsmarkers(orig, pushop):
+    if _dopushmarkers(pushop):
+        repo = pushop.repo
+        remote = pushop.remote
+        obsexcmsg(repo.ui, "computing relevant nodes\n")
+        revs = list(repo.revs('::%ln', pushop.futureheads))
+        unfi = repo.unfiltered()
+
+        if not usediscovery(repo):
+            # discovery disabled by user
+            repo.ui.status(obsdiscovery_skip_message)
+            return orig(pushop)
+
+        # look for an obs-discovery protocol we can use
+        discovery = None
+        for candidate in obsdiscoveries:
+            if candidate[0](repo, remote):
+                discovery = candidate[1]
+                break
+
+        if discovery is None:
+            # no discovery available, rely on core to push all relevants
+            # obs markers.
+            return orig(pushop)
+
+        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+                           % len(revs))
+        commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
+        # find the nodes where the relevant obsmarkers mismatches
+        nodes = discovery(pushop, commonrevs)
+
+        if nodes:
+            obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
+                               % len(nodes))
+            pushop.outobsmarkers = repo.obsstore.relevantmarkers(nodes)
+        else:
+            obsexcmsg(repo.ui, "markers already in sync\n")
+            pushop.outobsmarkers = []
+
+@eh.extsetup
+def _installobsmarkersdiscovery(ui):
+    olddisco = exchange.pushdiscoverymapping['obsmarker']
+
+    def newdisco(pushop):
+        _pushdiscoveryobsmarkers(olddisco, pushop)
+    exchange.pushdiscoverymapping['obsmarker'] = newdisco
+
+def buildpullobsmarkersboundaries(pullop, bundle2=True):
+    """small function returning the argument for pull markers call
+    may to contains 'heads' and 'common'. skip the key for None.
+
+    It is a separed function to play around with strategy for that."""
+    repo = pullop.repo
+    remote = pullop.remote
+    unfi = repo.unfiltered()
+    revs = unfi.revs('::(%ln - null)', pullop.common)
+    boundaries = {'heads': pullop.pulledsubset}
+    if not revs: # nothing common
+        boundaries['common'] = [node.nullid]
+        return boundaries
+
+    if not usediscovery(repo):
+        # discovery disabled by users.
+        repo.ui.status(obsdiscovery_skip_message)
+        boundaries['common'] = [node.nullid]
+        return boundaries
+
+    if bundle2 and _canobshashrange(repo, remote):
+        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+                  % len(revs))
+        boundaries['missing'] = findmissingrange(repo.ui, repo, pullop.remote,
+                                                 revs)
+    elif remote.capable('_evoext_obshash_0'):
+        obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
+                           % len(revs))
+        boundaries['common'] = findcommonobsmarkers(repo.ui, repo, remote, revs)
+    else:
+        boundaries['common'] = [node.nullid]
+    return boundaries
--- a/hgext3rd/evolve/obsexchange.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/obsexchange.py	Wed May 31 14:28:14 2017 +0200
@@ -18,6 +18,7 @@
 import socket
 
 from mercurial import (
+    bundle2,
     error,
     exchange,
     extensions,
@@ -98,7 +99,10 @@
             subset = [c.node() for c in repo.unfiltered().set('only(%ln, %ln)', heads, common)]
             subset += kwargs['evo_missing_nodes']
         markers = repo.obsstore.relevantmarkers(subset)
-        exchange.buildobsmarkerspart(bundler, markers)
+        if util.safehasattr(bundle2, 'buildobsmarkerspart'):
+            bundle2.buildobsmarkerspart(bundler, markers)
+        else:
+            exchange.buildobsmarkerspart(bundler, markers)
 
 # manual wrap up in extsetup because of the wireproto.commands mapping
 def _obscommon_capabilities(orig, repo, proto):
--- a/hgext3rd/evolve/obshistory.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/obshistory.py	Wed May 31 14:28:14 2017 +0200
@@ -7,11 +7,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+import re
+
 from mercurial import (
     cmdutil,
     commands,
     error,
     graphmod,
+    obsolete,
     node as nodemod,
     scmutil,
 )
@@ -25,9 +28,10 @@
 eh = exthelper.exthelper()
 
 @eh.command(
-    'olog',
+    'obslog|olog',
     [('G', 'graph', True, _("show the revision DAG")),
-     ('r', 'rev', [], _('show the specified revision or revset'), _('REV'))
+     ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
+     ('a', 'all', False, _('show all related changesets, not only precursors'))
     ] + commands.formatteropts,
     _('hg olog [OPTION]... [REV]'))
 def cmdobshistory(ui, repo, *revs, **opts):
@@ -157,14 +161,14 @@
             stack.pop()
     return False
 
-def _obshistorywalker(repo, revs):
+def _obshistorywalker(repo, revs, walksuccessors=False):
     """ Directly inspired by graphmod.dagwalker,
     walk the obs marker tree and yield
     (id, CHANGESET, ctx, [parentinfo]) tuples
     """
 
     # Get the list of nodes and links between them
-    candidates, nodesucc, nodeprec = _obshistorywalker_links(repo, revs)
+    candidates, nodesucc, nodeprec = _obshistorywalker_links(repo, revs, walksuccessors)
 
     # Shown, set of nodes presents in items
     shown = set()
@@ -215,15 +219,19 @@
             childrens = [(graphmod.PARENT, x) for x in nodeprec.get(cand, ())]
             yield (cand, 'M', changectx, childrens)
 
-def _obshistorywalker_links(repo, revs):
+def _obshistorywalker_links(repo, revs, walksuccessors=False):
     """ Iterate the obs history tree starting from revs, traversing
     each revision precursors recursively.
+    If walksuccessors is True, also check that every successor has been
+    walked, which ends up walking on all connected obs markers. It helps
+    getting a better view with splits and divergences.
     Return a tuple of:
     - The list of node crossed
     - The dictionnary of each node successors, values are a set
     - The dictionnary of each node precursors, values are a list
     """
     precursors = repo.obsstore.precursors
+    successors = repo.obsstore.successors
     nodec = repo.changelog.node
 
     # Parents, set of parents nodes seen during walking the graph for node
@@ -256,12 +264,21 @@
                 seen.add(precnode)
                 nodes.append(precnode)
 
+        # Also walk on successors if the option is enabled
+        if walksuccessors:
+            for successor in successors.get(node, ()):
+                for succnodeid in successor[1]:
+                    if succnodeid not in seen:
+                        seen.add(succnodeid)
+                        nodes.append(succnodeid)
+
     return sorted(seen), nodesucc, nodeprec
 
 def _debugobshistorygraph(ui, repo, revs, opts):
     displayer = obsmarker_printer(ui, repo.unfiltered(), None, opts, buffered=True)
     edges = graphmod.asciiedges
-    cmdutil.displaygraph(ui, repo, _obshistorywalker(repo.unfiltered(), revs), displayer, edges)
+    walker = _obshistorywalker(repo.unfiltered(), revs, opts.get('all', False))
+    cmdutil.displaygraph(ui, repo, walker, displayer, edges)
 
 def _debugobshistorysingle(fm, repo, revs):
     """ Display the obsolescence history for a single revision
@@ -337,6 +354,36 @@
 
     fm.write('debugobshistory.verb', '%s', verb,
              label="evolve.verb")
+
+    effectflag = metadata.get('ef1')
+    if effectflag is not None:
+        try:
+            effectflag = int(effectflag)
+        except ValueError:
+            effectflag = None
+    if effectflag:
+        effect = []
+
+        # XXX should be a dict
+        if effectflag & DESCCHANGED:
+            effect.append('description')
+        if effectflag & METACHANGED:
+            effect.append('meta')
+        if effectflag & USERCHANGED:
+            effect.append('user')
+        if effectflag & DATECHANGED:
+            effect.append('date')
+        if effectflag & BRANCHCHANGED:
+            effect.append('branch')
+        if effectflag & PARENTCHANGED:
+            effect.append('parent')
+        if effectflag & DIFFCHANGED:
+            effect.append('content')
+
+        if effect:
+            fmteffect = fm.formatlist(effect, 'debugobshistory.effect', sep=', ')
+            fm.write('debugobshistory.effect', '(%s)', fmteffect)
+
     fm.plain(' by ')
 
     fm.write('debugobshistory.marker_user', '%s', metadata['user'],
@@ -355,3 +402,205 @@
                  label="evolve.node")
 
     fm.plain("\n")
+
+# logic around storing and using effect flags
+DESCCHANGED = 1 << 0 # action changed the description
+METACHANGED = 1 << 1 # action change the meta
+PARENTCHANGED = 1 << 2 # action change the parent
+DIFFCHANGED = 1 << 3 # action change diff introduced by the changeset
+USERCHANGED = 1 << 4 # the user changed
+DATECHANGED = 1 << 5 # the date changed
+BRANCHCHANGED = 1 << 6 # the branch changed
+
+METABLACKLIST = [
+    re.compile('^__touch-noise__$'),
+    re.compile('^branch$'),
+    re.compile('^.*-source$'),
+    re.compile('^.*_source$'),
+    re.compile('^source$'),
+]
+
+def ismetablacklisted(metaitem):
+    """ Check that the key of a meta item (extrakey, extravalue) does not
+    match at least one of the blacklist pattern
+    """
+    metakey = metaitem[0]
+    for pattern in METABLACKLIST:
+        if pattern.match(metakey):
+            return False
+
+    return True
+
+def geteffectflag(relation):
+    """compute the effect flag by comparing the source and destination"""
+    effects = 0
+
+    source = relation[0]
+
+    for changectx in relation[1]:
+        # Check if description has changed
+        if changectx.description() != source.description():
+            effects |= DESCCHANGED
+
+        # Check if known meta has changed
+        if changectx.user() != source.user():
+            effects |= USERCHANGED
+
+        if changectx.date() != source.date():
+            effects |= DATECHANGED
+
+        if changectx.branch() != source.branch():
+            effects |= BRANCHCHANGED
+
+        # Check if other meta has changed
+        changeextra = changectx.extra().items()
+        ctxmeta = filter(ismetablacklisted, changeextra)
+
+        sourceextra = source.extra().items()
+        srcmeta = filter(ismetablacklisted, sourceextra)
+
+        if ctxmeta != srcmeta:
+            effects |= METACHANGED
+
+        # Check if at least one of the parent has changes
+        if changectx.parents() != source.parents():
+            effects |= PARENTCHANGED
+
+        if not _cmpdiff(source, changectx):
+            effects |= DIFFCHANGED
+
+    return effects
+
+def _prepare_hunk(hunk):
+    """Drop all information but the username and patch"""
+    cleanunk = []
+    for line in hunk.splitlines():
+        if line.startswith(b'# User') or not line.startswith(b'#'):
+            if line.startswith(b'@@'):
+                line = b'@@\n'
+            cleanunk.append(line)
+    return cleanunk
+
+def _getdifflines(iterdiff):
+    """return a cleaned up lines"""
+    try:
+        lines = iterdiff.next()
+    except StopIteration:
+        return None
+    return _prepare_hunk(lines)
+
+def _cmpdiff(leftctx, rightctx):
+    """return True if both ctx introduce the "same diff"
+
+    This is a first and basic implementation, with many shortcoming.
+    """
+    leftdiff = leftctx.diff(git=1)
+    rightdiff = rightctx.diff(git=1)
+    left, right = (0, 0)
+    while None not in (left, right):
+        left = _getdifflines(leftdiff)
+        right = _getdifflines(rightdiff)
+
+        if left != right:
+            return False
+    return True
+
+@eh.wrapfunction(obsolete, 'createmarkers')
+def createmarkerswithbits(orig, repo, relations, flag=0, date=None,
+                          metadata=None, **kwargs):
+    """compute 'effect-flag' and augment the created markers
+
+    Wrap obsolete.createmarker in order to compute the effect of each
+    relationship and store them as flag in the metadata.
+
+    While we experiment, we store flag in a metadata field. This field is
+    "versionned" to easilly allow moving to other meaning for flags.
+
+    The comparison of description or other infos just before creating the obs
+    marker might induce overhead in some cases. However it is a good place to
+    start since it automatically makes all markers creation recording more
+    meaningful data. In the future, we can introduce way for commands to
+    provide precomputed effect to avoid the overhead.
+    """
+    if not repo.ui.configbool('experimental', 'evolution.effect-flags', False):
+        return orig(repo, relations, flag, date, metadata, **kwargs)
+    if metadata is None:
+        metadata = {}
+    tr = repo.transaction('add-obsolescence-marker')
+    try:
+        for r in relations:
+            # Compute the effect flag for each obsmarker
+            effect = geteffectflag(r)
+
+            # Copy the metadata in order to add them, we copy because the
+            # effect flag might be different per relation
+            m = metadata.copy()
+            # we store the effect even if "0". This disctinct markers created
+            # without the feature with markers recording a no-op.
+            m['ef1'] = "%d" % effect
+
+            # And call obsolete.createmarkers for creating the obsmarker for real
+            orig(repo, [r], flag, date, m, **kwargs)
+
+        tr.close()
+    finally:
+        tr.release()
+
+def _getobsfate(successorssets):
+    """ Compute a changeset obsolescence fate based on his successorssets.
+    Successors can be the tipmost ones or the immediate ones.
+    Returns one fate in the following list:
+    - pruned
+    - diverged
+    - superseed
+    - superseed_split
+    """
+
+    if len(successorssets) == 0:
+        # The commit has been pruned
+        return 'pruned'
+    elif len(successorssets) > 1:
+        return 'diverged'
+    else:
+        # No divergence, only one set of successors
+        successors = successorssets[0]
+
+        if len(successors) == 1:
+            return 'superseed'
+        else:
+            return 'superseed_split'
+
+def _getobsfateandsuccs(repo, revnode, successorssets=None):
+    """ Return a tuple containing:
+    - the reason a revision is obsolete (diverged, pruned or superseed)
+    - the list of successors short node if the revision is neither pruned
+    or has diverged
+    """
+    if successorssets is None:
+        successorssets = obsolete.successorssets(repo, revnode)
+
+    fate = _getobsfate(successorssets)
+
+    # Apply node.short if we have no divergence
+    if len(successorssets) == 1:
+        successors = [nodemod.short(node_id) for node_id in successorssets[0]]
+    else:
+        successors = []
+        for succset in successorssets:
+            successors.append([nodemod.short(node_id) for node_id in succset])
+
+    return (fate, successors)
+
+def _humanizedobsfate(fate, successors):
+    """ Returns a humanized string for a changeset fate and its successors
+    """
+
+    if fate == 'pruned':
+        return 'pruned'
+    elif fate == 'diverged':
+        msgs = []
+        for successorsset in successors:
+            msgs.append('superseed as %s' % ','.join(successorsset))
+        return ' + '.join(msgs)
+    elif fate in ('superseed', 'superseed_split'):
+        return 'superseed as %s' % ','.join(successors)
--- a/hgext3rd/evolve/stablerange.py	Mon May 22 15:42:13 2017 +0200
+++ b/hgext3rd/evolve/stablerange.py	Wed May 31 14:28:14 2017 +0200
@@ -196,6 +196,8 @@
     depth = stablerange.depthrev
     length = stablerange.rangelength
     subranges = stablerange.subranges
+    if not revs:
+        raise error.Abort('no revisions specified')
     repo.stablerange.warmup(repo, max(revs))
     if opts['subranges']:
         ranges = subrangesclosure(repo, revs)
@@ -241,7 +243,7 @@
 
 class stablerange(object):
 
-    def __init__(self):
+    def __init__(self, lrusize=2000):
         # The point up to which we have data in cache
         self._tiprev = None
         self._tipnode = None
@@ -254,10 +256,10 @@
         # and then use the relevant top most part. This order is going to be
         # the same for all ranges headed at the same merge. So we cache these
         # value to reuse them accross the same invocation.
-        self._stablesortcache = {}
+        self._stablesortcache = util.lrucachedict(lrusize)
         # something useful to compute the above
         # mergerev -> stablesort, length
-        self._stablesortprepared = {}
+        self._stablesortprepared = util.lrucachedict(lrusize)
         # caching parent call # as we do so many of them
         self._parentscache = {}
         # The first part of the stable sorted list of revision of a merge will
@@ -304,12 +306,21 @@
 
         original = set(rangeheap)
         seen = 0
+        # progress report is showing up in the profile for small and fast
+        # repository so we build that complicated work around.
+        progress_each = 100
+        progress_last = time.time()
         heapify(rangeheap)
         while rangeheap:
             value = heappop(rangeheap)
             if value in original:
-                if not seen % 1000:
+                if not seen % progress_each:
+                    # if a lot of time passed, report more often
+                    progress_new = time.time()
+                    if (1 < progress_each) and (0.1 < progress_new - progress_last):
+                        progress_each /= 10
                     ui.progress(_("filling stablerange cache"), seen, total=nbrevs)
+                    progress_last = progress_new
                 seen += 1
                 original.remove(value) # might have been added from other source
             __, rangeid = value
@@ -383,7 +394,14 @@
             # note: In the general case we can just walk down and then request
             # data about the merge. But I'm not sure this function will be even
             # call for the general case.
-            allrevs = self._stablesortcache.get(headrev)
+
+            # Lrudict.get in hg-3.9 returns the lrunode instead of the
+            # value, use __getitem__ instead and catch the exception directly
+            try:
+                allrevs = self._stablesortcache[headrev]
+            except KeyError:
+                allrevs = None
+
             if allrevs is None:
                 allrevs = self._getrevsfrommerge(repo, headrev)
                 if allrevs is None:
@@ -432,8 +450,11 @@
             self._stablesortprepared[merge] = (sortedrevs, len(sortedrevs))
 
     def _getrevsfrommerge(self, repo, merge):
-        prepared = self._stablesortprepared.get(merge)
-        if prepared is None:
+        # Lrudict.get in hg-3.9 returns the lrunode instead of the
+        # value, use __getitem__ instead and catch the exception directly
+        try:
+            prepared = self._stablesortprepared[merge]
+        except KeyError:
             return None
 
         mergedepth = self.depthrev(repo, merge)
@@ -731,7 +752,9 @@
     _schemaversion = 0
 
     def __init__(self, repo):
-        super(sqlstablerange, self).__init__()
+        lrusize = repo.ui.configint('experimental', 'obshashrange.lru-size',
+                                    2000)
+        super(sqlstablerange, self).__init__(lrusize=lrusize)
         self._vfs = repo.vfs
         self._path = repo.vfs.join('cache/evoext_stablerange_v0.sqlite')
         self._cl = repo.unfiltered().changelog # (okay to keep an old one)
@@ -922,6 +945,9 @@
             tr = super(stablerangerepo, self).transaction(*args, **kwargs)
             if not repo.ui.configbool('experimental', 'obshashrange', False):
                 return tr
+            if not repo.ui.configbool('experimental', 'obshashrange.warm-cache',
+                                      True):
+                return tr
             reporef = weakref.ref(self)
 
             def _warmcache(tr):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/templatekw.py	Wed May 31 14:28:14 2017 +0200
@@ -0,0 +1,198 @@
+# Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
+#                Logilab SA        <contact@logilab.fr>
+#                Pierre-Yves David <pierre-yves.david@ens-lyon.org>
+#                Patrick Mezard <patrick@mezard.eu>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""evolve templates
+"""
+
+from . import (
+    exthelper,
+    obshistory
+)
+
+from mercurial import (
+    templatekw,
+    node,
+)
+
+eh = exthelper.exthelper()
+
+### template keywords
+# XXX it does not handle troubles well :-/
+
+@eh.templatekw('obsolete')
+def obsoletekw(repo, ctx, templ, **args):
+    """:obsolete: String. Whether the changeset is ``obsolete``.
+    """
+    if ctx.obsolete():
+        return 'obsolete'
+    return ''
+
+@eh.templatekw('troubles')
+def showtroubles(**args):
+    """:troubles: List of strings. Evolution troubles affecting the changeset
+    (zero or more of "unstable", "divergent" or "bumped")."""
+    ctx = args['ctx']
+    try:
+        # specify plural= explicitly to trigger TypeError on hg < 4.2
+        return templatekw.showlist('trouble', ctx.troubles(), args,
+                                   plural='troubles')
+    except TypeError:
+        return templatekw.showlist('trouble', ctx.troubles(), plural='troubles',
+                                   **args)
+
+def closestprecursors(repo, nodeid):
+    """ Yield the list of next precursors pointing on visible changectx nodes
+    """
+
+    precursors = repo.obsstore.precursors
+    stack = [nodeid]
+
+    while stack:
+        current = stack.pop()
+        currentpreccs = precursors.get(current, ())
+
+        for prec in currentpreccs:
+            precnodeid = prec[0]
+
+            if precnodeid in repo:
+                yield precnodeid
+            else:
+                stack.append(precnodeid)
+
+@eh.templatekw("precursors")
+def shownextvisibleprecursors(repo, ctx, **args):
+    """Returns a string containing the list if the closest successors
+    displayed
+    """
+    precursors = sorted(closestprecursors(repo, ctx.node()))
+
+    # <= hg-4.1 requires an explicite gen.
+    # we can use None once the support is dropped
+    #
+    # They also requires an iterator instead of an iterable.
+    gen = iter(" ".join(map(node.short, precursors)))
+    return templatekw._hybrid(gen.__iter__(), precursors, lambda x: {'precursor': x},
+                              lambda d: "%s" % node.short(d['precursor']))
+
+def closestsuccessors(repo, nodeid):
+    """ returns the closest visible successors sets instead.
+    """
+    return directsuccessorssets(repo, nodeid)
+
+@eh.templatekw("successors")
+def shownextvisiblesuccessors(repo, ctx, templ, **args):
+    """Returns a string of sets of successors for a changectx in this format:
+    [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2 while
+    also diverged into ctx3"""
+    if not ctx.obsolete():
+        return ''
+
+    ssets = closestsuccessors(repo, ctx.node())
+
+    data = []
+    gen = []
+    for ss in ssets:
+        subgen = '[%s]' % ', '.join(map(node.short, ss))
+        gen.append(subgen)
+        h = templatekw._hybrid(iter(subgen), ss, lambda x: {'successor': x},
+                               lambda d: "%s" % d["successor"])
+        data.append(h)
+
+    gen = ', '.join(gen)
+    return templatekw._hybrid(iter(gen), data, lambda x: {'successorset': x},
+                              lambda d: d["successorset"])
+
+@eh.templatekw("obsfate_quiet")
+def showobsfate_quiet(repo, ctx, templ, **args):
+    if not ctx.obsolete():
+        return ''
+
+    successorssets = closestsuccessors(repo, ctx.node())
+    return obshistory._humanizedobsfate(*obshistory._getobsfateandsuccs(repo, ctx, successorssets))
+
+# copy from mercurial.obsolete with a small change to stop at first known changeset.
+
+def directsuccessorssets(repo, initialnode, cache=None):
+    """return set of all direct successors of initial nodes
+    """
+
+    succmarkers = repo.obsstore.successors
+
+    # Stack of nodes we search successors sets for
+    toproceed = [initialnode]
+    # set version of above list for fast loop detection
+    # element added to "toproceed" must be added here
+    stackedset = set(toproceed)
+    if cache is None:
+        cache = {}
+    while toproceed:
+        current = toproceed[-1]
+        if current in cache:
+            stackedset.remove(toproceed.pop())
+        elif current != initialnode and current in repo:
+            # We have a valid direct successors.
+            cache[current] = [(current,)]
+        elif current not in succmarkers:
+            if current in repo:
+                # We have a valid last successors.
+                cache[current] = [(current,)]
+            else:
+                # Final obsolete version is unknown locally.
+                # Do not count that as a valid successors
+                cache[current] = []
+        else:
+            for mark in sorted(succmarkers[current]):
+                for suc in mark[1]:
+                    if suc not in cache:
+                        if suc in stackedset:
+                            # cycle breaking
+                            cache[suc] = []
+                        else:
+                            # case (3) If we have not computed successors sets
+                            # of one of those successors we add it to the
+                            # `toproceed` stack and stop all work for this
+                            # iteration.
+                            toproceed.append(suc)
+                            stackedset.add(suc)
+                            break
+                else:
+                    continue
+                break
+            else:
+                succssets = []
+                for mark in sorted(succmarkers[current]):
+                    # successors sets contributed by this marker
+                    markss = [[]]
+                    for suc in mark[1]:
+                        # cardinal product with previous successors
+                        productresult = []
+                        for prefix in markss:
+                            for suffix in cache[suc]:
+                                newss = list(prefix)
+                                for part in suffix:
+                                    # do not duplicated entry in successors set
+                                    # first entry wins.
+                                    if part not in newss:
+                                        newss.append(part)
+                                productresult.append(newss)
+                        markss = productresult
+                    succssets.extend(markss)
+                # remove duplicated and subset
+                seen = []
+                final = []
+                candidate = sorted(((set(s), s) for s in succssets if s),
+                                   key=lambda x: len(x[1]), reverse=True)
+                for setversion, listversion in candidate:
+                    for seenset in seen:
+                        if setversion.issubset(seenset):
+                            break
+                    else:
+                        final.append(listversion)
+                        seen.append(setversion)
+                final.reverse() # put small successors set first
+                cache[current] = final
+    return cache[initialnode]
--- a/tests/test-discovery-obshashrange.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-discovery-obshashrange.t	Wed May 31 14:28:14 2017 +0200
@@ -519,17 +519,17 @@
   $ hg debugobshashrange --subranges --rev 'heads(all())'
            rev         node        index         size        depth      obshash
              7 f69452c5b1af            0            7            7 000000000000
-             5 45f8b879de92            0            6            6 b8a4206b0fc6
+             5 45f8b879de92            0            6            6 7c49a958a9ac
              3 2dc09a01254d            0            4            4 8932bf980bb4
              7 f69452c5b1af            4            3            7 000000000000
              3 2dc09a01254d            2            2            4 ce1937ca1278
-             5 45f8b879de92            4            2            6 31fc49d36a59
+             5 45f8b879de92            4            2            6 c6795525c540
              1 66f7d451a68b            0            2            2 327c7dd73d29
              6 c8d03c1b5e94            4            2            6 89755fd39e6d
              2 01241442b3c2            2            1            3 1ed3c61fb39a
              0 1ea73414a91b            0            1            1 000000000000
              3 2dc09a01254d            3            1            4 26f996446ecb
-             5 45f8b879de92            5            1            6 1a0c08180b65
+             5 45f8b879de92            5            1            6 796507769034
              1 66f7d451a68b            1            1            2 327c7dd73d29
              4 bebd167eb94d            4            1            5 b21465ecb790
              6 c8d03c1b5e94            5            1            6 446c2dc3bce5
@@ -571,17 +571,17 @@
   $ hg debugobshashrange --subranges --rev 'heads(all())'
            rev         node        index         size        depth      obshash
              7 f69452c5b1af            0            7            7 000000000000
-             5 45f8b879de92            0            6            6 b8a4206b0fc6
+             5 45f8b879de92            0            6            6 7c49a958a9ac
              3 2dc09a01254d            0            4            4 8932bf980bb4
              7 f69452c5b1af            4            3            7 000000000000
              3 2dc09a01254d            2            2            4 ce1937ca1278
-             5 45f8b879de92            4            2            6 31fc49d36a59
+             5 45f8b879de92            4            2            6 c6795525c540
              1 66f7d451a68b            0            2            2 327c7dd73d29
              6 c8d03c1b5e94            4            2            6 89755fd39e6d
              2 01241442b3c2            2            1            3 1ed3c61fb39a
              0 1ea73414a91b            0            1            1 000000000000
              3 2dc09a01254d            3            1            4 26f996446ecb
-             5 45f8b879de92            5            1            6 1a0c08180b65
+             5 45f8b879de92            5            1            6 796507769034
              1 66f7d451a68b            1            1            2 327c7dd73d29
              4 bebd167eb94d            4            1            5 b21465ecb790
              6 c8d03c1b5e94            5            1            6 446c2dc3bce5
@@ -616,18 +616,18 @@
   $ hg debugobshashrange --subranges --rev 'heads(all())'
            rev         node        index         size        depth      obshash
              8 4de32a90b66c            0            8            8 c7f1f7e9925b
-             5 45f8b879de92            0            6            6 b8a4206b0fc6
+             5 45f8b879de92            0            6            6 7c49a958a9ac
              3 2dc09a01254d            0            4            4 8932bf980bb4
              8 4de32a90b66c            4            4            8 c681c3e58c27
              3 2dc09a01254d            2            2            4 ce1937ca1278
-             5 45f8b879de92            4            2            6 31fc49d36a59
+             5 45f8b879de92            4            2            6 c6795525c540
              8 4de32a90b66c            6            2            8 033544c939f0
              1 66f7d451a68b            0            2            2 327c7dd73d29
              6 c8d03c1b5e94            4            2            6 89755fd39e6d
              2 01241442b3c2            2            1            3 1ed3c61fb39a
              0 1ea73414a91b            0            1            1 000000000000
              3 2dc09a01254d            3            1            4 26f996446ecb
-             5 45f8b879de92            5            1            6 1a0c08180b65
+             5 45f8b879de92            5            1            6 796507769034
              8 4de32a90b66c            7            1            8 033544c939f0
              1 66f7d451a68b            1            1            2 327c7dd73d29
              4 bebd167eb94d            4            1            5 b21465ecb790
@@ -745,18 +745,18 @@
   $ hg debugobshashrange --subranges --rev 'heads(all())'
            rev         node        index         size        depth      obshash
              7 4de32a90b66c            0            8            8 c7f1f7e9925b
-             8 45f8b879de92            0            6            6 b8a4206b0fc6
+             8 45f8b879de92            0            6            6 7c49a958a9ac
              3 2dc09a01254d            0            4            4 8932bf980bb4
              7 4de32a90b66c            4            4            8 c681c3e58c27
              3 2dc09a01254d            2            2            4 ce1937ca1278
-             8 45f8b879de92            4            2            6 31fc49d36a59
+             8 45f8b879de92            4            2            6 c6795525c540
              7 4de32a90b66c            6            2            8 033544c939f0
              1 66f7d451a68b            0            2            2 327c7dd73d29
              5 c8d03c1b5e94            4            2            6 89755fd39e6d
              2 01241442b3c2            2            1            3 1ed3c61fb39a
              0 1ea73414a91b            0            1            1 000000000000
              3 2dc09a01254d            3            1            4 26f996446ecb
-             8 45f8b879de92            5            1            6 1a0c08180b65
+             8 45f8b879de92            5            1            6 796507769034
              7 4de32a90b66c            7            1            8 033544c939f0
              1 66f7d451a68b            1            1            2 327c7dd73d29
              4 bebd167eb94d            4            1            5 b21465ecb790
--- a/tests/test-evolve-list.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-evolve-list.t	Wed May 31 14:28:14 2017 +0200
@@ -72,6 +72,10 @@
   a922b3733e98: b
     divergent: c882616e9d84 (draft) (precursor d2ae7f538514)
   
+  $ hg evolve --list --rev c882616e9d84
+  c882616e9d84: b
+    divergent: a922b3733e98 (draft) (precursor d2ae7f538514)
+  
   $ hg phase -p a922b3733e98
   $ hg evolve --list
   c882616e9d84: b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-templates.t	Wed May 31 14:28:14 2017 +0200
@@ -0,0 +1,773 @@
+This test file test the various templates for precursors and successors.
+
+Global setup
+============
+
+  $ . $TESTDIR/testlib/common.sh
+  $ cat >> $HGRCPATH <<EOF
+  > [ui]
+  > interactive = true
+  > [phases]
+  > publish=False
+  > [extensions]
+  > evolve =
+  > [alias]
+  > tlog = log -G -T '{node|short}\
+  >     {if(precursors, "\n  Precursors: {precursors}")}\
+  >     {if(precursors, "\n  semi-colon: {join(precursors, "; ")}")}\
+  >     {if(successors, "\n  Successors: {successors}")}\
+  >     {if(successors, "\n  semi-colon: {join(successors, "; ")}")}\
+  >     {if(successors, "\n  Fate: {obsfate_quiet}")}\n'
+  > EOF
+
+Test templates on amended commit
+================================
+
+Test setup
+----------
+
+  $ hg init $TESTTMP/templates-local-amend
+  $ cd $TESTTMP/templates-local-amend
+  $ mkcommit ROOT
+  $ mkcommit A0
+  $ echo 42 >> A0
+  $ hg amend -m "A1"
+  $ hg amend -m "A2"
+  $ hg log --hidden -G
+  @  changeset:   4:d004c8f274b9
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A2
+  |
+  | x  changeset:   3:a468dc9b3633
+  |/   parent:      0:ea207398892e
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A1
+  |
+  | x  changeset:   2:f137d23bb3e1
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     temporary amend commit for 471f378eab4c
+  | |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+Check templates
+---------------
+  $ hg up 'desc(A0)' --hidden
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (471f378eab4c)
+  (use 'hg evolve' to update to its successor: d004c8f274b9)
+
+Precursors template should show current revision as it is the working copy
+  $ hg tlog
+  o  d004c8f274b9
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | @  471f378eab4c
+  |/     Successors: [d004c8f274b9]
+  |      semi-colon: [d004c8f274b9]
+  |      Fate: superseed as d004c8f274b9
+  o  ea207398892e
+  
+  $ hg up 'desc(A1)' --hidden
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (a468dc9b3633)
+  (use 'hg evolve' to update to its successor: d004c8f274b9)
+
+Precursors template should show current revision as it is the working copy
+  $ hg tlog
+  o  d004c8f274b9
+  |    Precursors: a468dc9b3633
+  |    semi-colon: a468dc9b3633
+  | @  a468dc9b3633
+  |/     Successors: [d004c8f274b9]
+  |      semi-colon: [d004c8f274b9]
+  |      Fate: superseed as d004c8f274b9
+  o  ea207398892e
+  
+Precursors template should show the precursor as we force its display with
+--hidden  
+  $ hg tlog --hidden
+  o  d004c8f274b9
+  |    Precursors: a468dc9b3633
+  |    semi-colon: a468dc9b3633
+  | @  a468dc9b3633
+  |/     Precursors: 471f378eab4c
+  |      semi-colon: 471f378eab4c
+  |      Successors: [d004c8f274b9]
+  |      semi-colon: [d004c8f274b9]
+  |      Fate: superseed as d004c8f274b9
+  | x  f137d23bb3e1
+  | |
+  | x  471f378eab4c
+  |/     Successors: [a468dc9b3633]
+  |      semi-colon: [a468dc9b3633]
+  |      Fate: superseed as a468dc9b3633
+  o  ea207398892e
+  
+
+  $ hg up 'desc(A2)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg tlog
+  @  d004c8f274b9
+  |
+  o  ea207398892e
+  
+  $ hg tlog --hidden
+  @  d004c8f274b9
+  |    Precursors: a468dc9b3633
+  |    semi-colon: a468dc9b3633
+  | x  a468dc9b3633
+  |/     Precursors: 471f378eab4c
+  |      semi-colon: 471f378eab4c
+  |      Successors: [d004c8f274b9]
+  |      semi-colon: [d004c8f274b9]
+  |      Fate: superseed as d004c8f274b9
+  | x  f137d23bb3e1
+  | |
+  | x  471f378eab4c
+  |/     Successors: [a468dc9b3633]
+  |      semi-colon: [a468dc9b3633]
+  |      Fate: superseed as a468dc9b3633
+  o  ea207398892e
+  
+
+Test templates with splitted commit
+===================================
+
+  $ hg init $TESTTMP/templates-local-split
+  $ cd $TESTTMP/templates-local-split
+  $ mkcommit ROOT
+  $ echo 42 >> a
+  $ echo 43 >> b
+  $ hg commit -A -m "A0"
+  adding a
+  adding b
+  $ hg log --hidden -G
+  @  changeset:   1:471597cad322
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ hg split -r 'desc(A0)' -d "0 0" << EOF
+  > y
+  > y
+  > n
+  > n
+  > y
+  > y
+  > EOF
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  adding a
+  adding b
+  diff --git a/a b/a
+  new file mode 100644
+  examine changes to 'a'? [Ynesfdaq?] y
+  
+  @@ -0,0 +1,1 @@
+  +42
+  record change 1/2 to 'a'? [Ynesfdaq?] y
+  
+  diff --git a/b b/b
+  new file mode 100644
+  examine changes to 'b'? [Ynesfdaq?] n
+  
+  created new head
+  Done splitting? [yN] n
+  diff --git a/b b/b
+  new file mode 100644
+  examine changes to 'b'? [Ynesfdaq?] y
+  
+  @@ -0,0 +1,1 @@
+  +43
+  record this change to 'b'? [Ynesfdaq?] y
+  
+  no more change to split
+
+  $ hg log --hidden -G
+  @  changeset:   3:f257fde29c7a
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  o  changeset:   2:337fec4d2edc
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  | x  changeset:   1:471597cad322
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+
+Check templates
+---------------
+
+  $ hg up 'obsolete()' --hidden
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (471597cad322)
+  (use 'hg evolve' to update to its tipmost successor: 337fec4d2edc, f257fde29c7a)
+
+Precursors template should show current revision as it is the working copy
+  $ hg tlog
+  o  f257fde29c7a
+  |    Precursors: 471597cad322
+  |    semi-colon: 471597cad322
+  o  337fec4d2edc
+  |    Precursors: 471597cad322
+  |    semi-colon: 471597cad322
+  | @  471597cad322
+  |/     Successors: [337fec4d2edc, f257fde29c7a]
+  |      semi-colon: [337fec4d2edc, f257fde29c7a]
+  |      Fate: superseed as 337fec4d2edc,f257fde29c7a
+  o  ea207398892e
+  
+  $ hg up f257fde29c7a
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Precursors template should not show a precursor as it's not displayed in the
+log
+  $ hg tlog
+  @  f257fde29c7a
+  |
+  o  337fec4d2edc
+  |
+  o  ea207398892e
+  
+Precursors template should show the precursor as we force its display with
+--hidden
+  $ hg tlog --hidden
+  @  f257fde29c7a
+  |    Precursors: 471597cad322
+  |    semi-colon: 471597cad322
+  o  337fec4d2edc
+  |    Precursors: 471597cad322
+  |    semi-colon: 471597cad322
+  | x  471597cad322
+  |/     Successors: [337fec4d2edc, f257fde29c7a]
+  |      semi-colon: [337fec4d2edc, f257fde29c7a]
+  |      Fate: superseed as 337fec4d2edc,f257fde29c7a
+  o  ea207398892e
+  
+Test templates with folded commit
+==============================
+
+Test setup
+----------
+
+  $ hg init $TESTTMP/templates-local-fold
+  $ cd $TESTTMP/templates-local-fold
+  $ mkcommit ROOT
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg log --hidden -G
+  @  changeset:   2:0dec01379d3b
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     B0
+  |
+  o  changeset:   1:471f378eab4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ hg fold --exact -r 'desc(A0) + desc(B0)' --date "0 0" -m "C0"
+  2 changesets folded
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log --hidden -G
+  @  changeset:   3:eb5a0daa2192
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     C0
+  |
+  | x  changeset:   2:0dec01379d3b
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     B0
+  | |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+Check templates
+---------------
+
+  $ hg up 'desc(A0)' --hidden
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory parent is obsolete! (471f378eab4c)
+  (use 'hg evolve' to update to its successor: eb5a0daa2192)
+
+Precursors template should show current revision as it is the working copy
+  $ hg tlog
+  o  eb5a0daa2192
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | @  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+  $ hg up 'desc(B0)' --hidden
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (0dec01379d3b)
+  (use 'hg evolve' to update to its successor: eb5a0daa2192)
+
+Precursors template should show both precursors as they should be both
+displayed
+  $ hg tlog
+  o  eb5a0daa2192
+  |    Precursors: 0dec01379d3b 471f378eab4c
+  |    semi-colon: 0dec01379d3b; 471f378eab4c
+  | @  0dec01379d3b
+  | |    Successors: [eb5a0daa2192]
+  | |    semi-colon: [eb5a0daa2192]
+  | |    Fate: superseed as eb5a0daa2192
+  | x  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+  $ hg up 'desc(C0)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Precursors template should not show precursors as it's not displayed in the
+log
+  $ hg tlog
+  @  eb5a0daa2192
+  |
+  o  ea207398892e
+  
+Precursors template should show both precursors as we force its display with
+--hidden
+  $ hg tlog --hidden
+  @  eb5a0daa2192
+  |    Precursors: 0dec01379d3b 471f378eab4c
+  |    semi-colon: 0dec01379d3b; 471f378eab4c
+  | x  0dec01379d3b
+  | |    Successors: [eb5a0daa2192]
+  | |    semi-colon: [eb5a0daa2192]
+  | |    Fate: superseed as eb5a0daa2192
+  | x  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+
+Test templates with divergence
+==============================
+
+Test setup
+----------
+
+  $ hg init $TESTTMP/templates-local-divergence
+  $ cd $TESTTMP/templates-local-divergence
+  $ mkcommit ROOT
+  $ mkcommit A0
+  $ hg amend -m "A1"
+  $ hg log --hidden -G
+  @  changeset:   2:fdf9bde5129a
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A1
+  |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ hg update --hidden 'desc(A0)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (471f378eab4c)
+  (use 'hg evolve' to update to its successor: fdf9bde5129a)
+  $ hg amend -m "A2"
+  2 new divergent changesets
+  $ hg log --hidden -G
+  @  changeset:   3:65b757b745b9
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A2
+  |
+  | o  changeset:   2:fdf9bde5129a
+  |/   parent:      0:ea207398892e
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A1
+  |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ hg amend -m 'A3'
+
+Check templates
+---------------
+
+  $ hg up 'desc(A0)' --hidden
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (471f378eab4c)
+  (471f378eab4c has diverged, use 'hg evolve -list --divergent' to resolve the issue)
+
+Precursors template should show current revision as it is the working copy
+  $ hg tlog
+  o  019fadeab383
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | o  fdf9bde5129a
+  |/     Precursors: 471f378eab4c
+  |      semi-colon: 471f378eab4c
+  | @  471f378eab4c
+  |/     Successors: [fdf9bde5129a], [019fadeab383]
+  |      semi-colon: [fdf9bde5129a]; [019fadeab383]
+  |      Fate: superseed as fdf9bde5129a + superseed as 019fadeab383
+  o  ea207398892e
+  
+  $ hg up 'desc(A1)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Precursors template should not show precursors as it's not displayed in the
+log
+  $ hg tlog
+  o  019fadeab383
+  |
+  | @  fdf9bde5129a
+  |/
+  o  ea207398892e
+  
+Precursors template should a precursor as we force its display with --hidden
+  $ hg tlog --hidden
+  o  019fadeab383
+  |    Precursors: 65b757b745b9
+  |    semi-colon: 65b757b745b9
+  | x  65b757b745b9
+  |/     Precursors: 471f378eab4c
+  |      semi-colon: 471f378eab4c
+  |      Successors: [019fadeab383]
+  |      semi-colon: [019fadeab383]
+  |      Fate: superseed as 019fadeab383
+  | @  fdf9bde5129a
+  |/     Precursors: 471f378eab4c
+  |      semi-colon: 471f378eab4c
+  | x  471f378eab4c
+  |/     Successors: [fdf9bde5129a], [65b757b745b9]
+  |      semi-colon: [fdf9bde5129a]; [65b757b745b9]
+  |      Fate: superseed as fdf9bde5129a + superseed as 65b757b745b9
+  o  ea207398892e
+  
+Test templates with amended + folded commit
+===========================================
+
+Test setup
+----------
+
+  $ hg init $TESTTMP/templates-local-amend-fold
+  $ cd $TESTTMP/templates-local-amend-fold
+  $ mkcommit ROOT
+  $ mkcommit A0
+  $ mkcommit B0
+  $ hg amend -m "B1"
+  $ hg log --hidden -G
+  @  changeset:   3:b7ea6d14e664
+  |  tag:         tip
+  |  parent:      1:471f378eab4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     B1
+  |
+  | x  changeset:   2:0dec01379d3b
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     B0
+  |
+  o  changeset:   1:471f378eab4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ hg fold --exact -r 'desc(A0) + desc(B1)' --date "0 0" -m "C0"
+  2 changesets folded
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log --hidden -G
+  @  changeset:   4:eb5a0daa2192
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     C0
+  |
+  | x  changeset:   3:b7ea6d14e664
+  | |  parent:      1:471f378eab4c
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     B1
+  | |
+  | | x  changeset:   2:0dec01379d3b
+  | |/   user:        test
+  | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    summary:     B0
+  | |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+Check templates
+---------------
+
+  $ hg up 'desc(A0)' --hidden
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory parent is obsolete! (471f378eab4c)
+  (use 'hg evolve' to update to its successor: eb5a0daa2192)
+  $ hg tlog
+  o  eb5a0daa2192
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | @  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+  $ hg up 'desc(B0)' --hidden
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (0dec01379d3b)
+  (use 'hg evolve' to update to its successor: eb5a0daa2192)
+  $ hg tlog
+  o  eb5a0daa2192
+  |    Precursors: 0dec01379d3b 471f378eab4c
+  |    semi-colon: 0dec01379d3b; 471f378eab4c
+  | @  0dec01379d3b
+  | |    Successors: [eb5a0daa2192]
+  | |    semi-colon: [eb5a0daa2192]
+  | |    Fate: superseed as eb5a0daa2192
+  | x  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+  $ hg up 'desc(B1)' --hidden
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory parent is obsolete! (b7ea6d14e664)
+  (use 'hg evolve' to update to its successor: eb5a0daa2192)
+  $ hg tlog
+  o  eb5a0daa2192
+  |    Precursors: 471f378eab4c b7ea6d14e664
+  |    semi-colon: 471f378eab4c; b7ea6d14e664
+  | @  b7ea6d14e664
+  | |    Successors: [eb5a0daa2192]
+  | |    semi-colon: [eb5a0daa2192]
+  | |    Fate: superseed as eb5a0daa2192
+  | x  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+  $ hg up 'desc(C0)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg tlog
+  @  eb5a0daa2192
+  |
+  o  ea207398892e
+  
+  $ hg tlog --hidden
+  @  eb5a0daa2192
+  |    Precursors: 471f378eab4c b7ea6d14e664
+  |    semi-colon: 471f378eab4c; b7ea6d14e664
+  | x  b7ea6d14e664
+  | |    Precursors: 0dec01379d3b
+  | |    semi-colon: 0dec01379d3b
+  | |    Successors: [eb5a0daa2192]
+  | |    semi-colon: [eb5a0daa2192]
+  | |    Fate: superseed as eb5a0daa2192
+  | | x  0dec01379d3b
+  | |/     Successors: [b7ea6d14e664]
+  | |      semi-colon: [b7ea6d14e664]
+  | |      Fate: superseed as b7ea6d14e664
+  | x  471f378eab4c
+  |/     Successors: [eb5a0daa2192]
+  |      semi-colon: [eb5a0daa2192]
+  |      Fate: superseed as eb5a0daa2192
+  o  ea207398892e
+  
+
+Test template with pushed and pulled obs markers
+==============================================
+
+Test setup
+----------
+
+  $ hg init $TESTTMP/templates-local-remote-markers-1
+  $ cd $TESTTMP/templates-local-remote-markers-1
+  $ mkcommit ROOT
+  $ mkcommit A0  
+  $ hg clone $TESTTMP/templates-local-remote-markers-1 $TESTTMP/templates-local-remote-markers-2
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd $TESTTMP/templates-local-remote-markers-2
+  $ hg log --hidden -G
+  @  changeset:   1:471f378eab4c
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ cd $TESTTMP/templates-local-remote-markers-1
+  $ hg amend -m "A1"
+  $ hg amend -m "A2"
+  $ hg log --hidden -G
+  @  changeset:   3:7a230b46bf61
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A2
+  |
+  | x  changeset:   2:fdf9bde5129a
+  |/   parent:      0:ea207398892e
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A1
+  |
+  | x  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+  $ cd $TESTTMP/templates-local-remote-markers-2
+  $ hg pull
+  pulling from $TESTTMP/templates-local-remote-markers-1
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 0 changes to 1 files (+1 heads)
+  2 new obsolescence markers
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+  working directory parent is obsolete! (471f378eab4c)
+  (use 'hg evolve' to update to its successor: 7a230b46bf61)
+  $ hg log --hidden -G
+  o  changeset:   2:7a230b46bf61
+  |  tag:         tip
+  |  parent:      0:ea207398892e
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     A2
+  |
+  | @  changeset:   1:471f378eab4c
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     A0
+  |
+  o  changeset:   0:ea207398892e
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     ROOT
+  
+
+Check templates
+---------------
+
+  $ hg tlog
+  o  7a230b46bf61
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | @  471f378eab4c
+  |/     Successors: [7a230b46bf61]
+  |      semi-colon: [7a230b46bf61]
+  |      Fate: superseed as 7a230b46bf61
+  o  ea207398892e
+  
+  $ hg up 'desc(A2)'
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg tlog
+  @  7a230b46bf61
+  |
+  o  ea207398892e
+  
+  $ hg tlog --hidden
+  @  7a230b46bf61
+  |    Precursors: 471f378eab4c
+  |    semi-colon: 471f378eab4c
+  | x  471f378eab4c
+  |/     Successors: [7a230b46bf61]
+  |      semi-colon: [7a230b46bf61]
+  |      Fate: superseed as 7a230b46bf61
+  o  ea207398892e
+  
--- a/tests/test-evolve.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-evolve.t	Wed May 31 14:28:14 2017 +0200
@@ -779,6 +779,17 @@
       more than 2 successors:         0
       available  keys:
                  user:               10
+  marker size:
+      format v1:
+          smallest length:           69
+          longer length:             69
+          median length:             69
+          mean length:               69
+      format v0:
+          smallest length:           * (glob)
+          longer length:             * (glob)
+          median length:             * (glob)
+          mean length:               * (glob)
   disconnected clusters:              1
           any known node:             1
           smallest length:           10
@@ -1477,121 +1488,3 @@
 
   $ hg status newlyadded
   A newlyadded
-
-hg metaedit
------------
-
-  $ hg update --clean .
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ rm newlyadded
-  $ hg metaedit -r 0
-  abort: cannot edit commit information for public revisions
-  [255]
-  $ hg metaedit --fold
-  abort: revisions must be specified with --fold
-  [255]
-  $ hg metaedit -r 0 --fold
-  abort: cannot fold public revisions
-  [255]
-  $ hg metaedit '36 + 42' --fold
-  abort: cannot fold non-linear revisions (multiple roots given)
-  [255]
-  $ hg metaedit '36::39 + 41' --fold
-  abort: cannot fold non-linear revisions (multiple heads given)
-  [255]
-check that metaedit respects allowunstable
-  $ hg metaedit '.^' --config 'experimental.evolution=createmarkers, allnewcommands'
-  abort: cannot edit commit information in the middle of a stack
-  (c904da5245b0 will become unstable and new unstable changes are not allowed)
-  [255]
-  $ hg metaedit '18::20' --fold --config 'experimental.evolution=createmarkers, allnewcommands'
-  abort: cannot fold chain not ending with a head or with branching
-  (new unstable changesets are not allowed)
-  [255]
-  $ hg metaedit --user foobar
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg log --template '{rev}: {author}\n' -r '42:' --hidden
-  42: test
-  43: foobar
-  $ hg log --template '{rev}: {author}\n' -r .
-  43: foobar
-
-TODO: support this
-  $ hg metaedit '.^::.'
-  abort: editing multiple revisions without --fold is not currently supported
-  [255]
-
-  $ HGEDITOR=cat hg metaedit '.^::.' --fold
-  HG: This is a fold of 2 changesets.
-  HG: Commit message of changeset 41.
-  
-  amended
-  
-  HG: Commit message of changeset 43.
-  
-  will be evolved safely
-  
-  
-  
-  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
-  HG: Leave message empty to abort commit.
-  HG: --
-  HG: user: test
-  HG: branch 'default'
-  HG: changed a
-  HG: changed newfile
-  2 changesets folded
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-  $ glog -r .
-  @  44:41bf1183869c@default(draft) amended
-  |
-  ~
-
-no new commit is created here because the date is the same
-  $ HGEDITOR=cat hg metaedit
-  amended
-  
-  
-  will be evolved safely
-  
-  
-  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
-  HG: Leave message empty to abort commit.
-  HG: --
-  HG: user: test
-  HG: branch 'default'
-  HG: changed a
-  HG: changed newfile
-  nothing changed
-
-  $ glog -r '.^::.'
-  @  44:41bf1183869c@default(draft) amended
-  |
-  o  36:43c3f5ef149f@default(draft) add uu
-  |
-  ~
-
-TODO: don't create a new commit in this case
-  $ hg metaedit --config defaults.metaedit=
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg log -r '.^::.' --template '{rev}: {desc|firstline}\n'
-  36: add uu
-  45: amended
-
-  $ hg up .^
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg metaedit --user foobar2 45
-  $ hg log --template '{rev}: {author}\n' -r '42:' --hidden
-  42: test
-  43: foobar
-  44: test
-  45: test
-  46: foobar2
-  $ hg diff -r 45 -r 46 --hidden
-
-'fold' one commit
-  $ hg metaedit 39 --fold --user foobar3
-  1 changesets folded
-  $ hg log -r 47 --template '{rev}: {author}\n'
-  47: foobar3
--- a/tests/test-exchange-obsmarkers-case-B1.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B1.t	Wed May 31 14:28:14 2017 +0200
@@ -75,7 +75,7 @@
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 926d9d84b97b3483891ae983990ad87c1f7827e9
-  f6fbb35d8ac958bbe70035e4c789c18471cdc0af e041f7ff1c7bd5501c7ab602baa35f0873128021
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af c2398c6305068b6b377f36402c507b713a7c586f
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B2.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B2.t	Wed May 31 14:28:14 2017 +0200
@@ -65,7 +65,7 @@
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 52a5380bc04783a9ad43bb2ab2f47a02ef02adcc
-  f5bc6836db60e308a17ba08bf050154ba9c4fad7 c5a567339e205e8cc4c494e4fb82944daaec449c
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 6892277170c13fec6712303d639965a454b5cabf
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B3.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B3.t	Wed May 31 14:28:14 2017 +0200
@@ -78,7 +78,7 @@
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 0000000000000000000000000000000000000000
   35b1839966785d5703a01607229eea932db42f87 631ab4cd02ffa1d144dc8f32a18be574076031e3
-  e56289ab6378dc752fd7965f8bf66b58bda740bd 47c9d2d8db5d4b1eddd0266329ad260ccc84772c
+  e56289ab6378dc752fd7965f8bf66b58bda740bd a37fa02ad96f2e8ecce7080e73cfe22af8e1b14f
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B4.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B4.t	Wed May 31 14:28:14 2017 +0200
@@ -93,7 +93,7 @@
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 1900882e85db10a1dc5bc7748f436a8a834356c6
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 c27e764c783f451ef3aa40daf2a3795e6674cd06
   f6fbb35d8ac958bbe70035e4c789c18471cdc0af 907beff79fdff2b82b5d3bed7989107a6d744508
-  7f7f229b13a629a5b20581c6cb723f4e2ca54bed c27e764c783f451ef3aa40daf2a3795e6674cd06
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 86e6b5a5ad828d83b3205ea4ca11154972da19a1
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B5.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B5.t	Wed May 31 14:28:14 2017 +0200
@@ -100,7 +100,7 @@
   6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 13bd00d88332fcd3fe634ed42f9d35c9cfc06398
   1d0f3cd253006f014c7687a78abbc9287db4101d 01d985a82467333a4de7a5b4e8a0de3286f8bda8
   e5ea8f9c73143125d36658e90ef70c6d2027a5b7 d2b1159bcf3694aabc3674785b1859544c35357d
-  069b05c3876d56f62895e853a501ea58ea85f68d d00e3201fcf83a1bf42e70757f07b45bdd77a220
+  069b05c3876d56f62895e853a501ea58ea85f68d a07163ee7e7cda4065f7593715b7b12f833f7065
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B6.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B6.t	Wed May 31 14:28:14 2017 +0200
@@ -77,7 +77,7 @@
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 86e41541149f4b6cccc5fd131d744d8e83a681e5
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 f2e05412d3f1d5bc1ae647cf9efc43e0399c26ca
   962ecf6b1afc94e15c7e48fdfb76ef8abd11372b 974507d1c466d0aa86d288836194339ed3b98736
-  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 04e03a8959d8a39984e6a8f4a16fba975b364747
+  f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 1e0b6dce792c229c865a543c6f8964b4bba5fb5a
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-B7.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-B7.t	Wed May 31 14:28:14 2017 +0200
@@ -71,7 +71,7 @@
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 926d9d84b97b3483891ae983990ad87c1f7827e9
-  f6fbb35d8ac958bbe70035e4c789c18471cdc0af e041f7ff1c7bd5501c7ab602baa35f0873128021
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af c2398c6305068b6b377f36402c507b713a7c586f
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-C1.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-C1.t	Wed May 31 14:28:14 2017 +0200
@@ -75,8 +75,8 @@
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 1ce18e5a71f78d443a80c819f2f7197c4706af70
-  f5bc6836db60e308a17ba08bf050154ba9c4fad7 92af733686ce7e0469d8b2b87b4612a4c2d33468
-  f6fbb35d8ac958bbe70035e4c789c18471cdc0af 3800aeba3728457abb9c508c94f6abc59e698c55
+  f5bc6836db60e308a17ba08bf050154ba9c4fad7 5c3c935df6f4007c633c3386d6f58b22c274809e
+  f6fbb35d8ac958bbe70035e4c789c18471cdc0af bccb3d243420ef26782fa11f209830db360c34b2
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-C2.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-C2.t	Wed May 31 14:28:14 2017 +0200
@@ -80,7 +80,7 @@
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f 72f95b7b9fa12243aeb90433d211f2c38263da31
-  06055a7959d4128e6e3bccfd01482e83a2db8a3a 58ecf9a107b10986d88da605eb0d03b7f24ae486
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 9d758cd0bf02f27e9b7de5665b10ceb1dc8bb1f1
   e5ea8f9c73143125d36658e90ef70c6d2027a5b7 289cb0d058c81c763eca8bb438657dba9a7ba646
   obshashrange
   ============
--- a/tests/test-exchange-obsmarkers-case-C3.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-C3.t	Wed May 31 14:28:14 2017 +0200
@@ -84,8 +84,8 @@
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 40be80b35671116f2c61ef25797806536a6eb5a0
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f beac7228bbe708bc7c9181c3c27f8a17f21dbd9f
-  06055a7959d4128e6e3bccfd01482e83a2db8a3a 8b648bd67281e9e525919285ac7b3bb2836c2f02
-  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 dcd2b566ad0983333be704afdc205066e1a6b742
+  06055a7959d4128e6e3bccfd01482e83a2db8a3a 04b20150f38991d297ecfe0bf0f77deb816aed9d
+  e5ea8f9c73143125d36658e90ef70c6d2027a5b7 a59f7d5ea437389a33d2e98b9b85ba1d568a743e
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- a/tests/test-exchange-obsmarkers-case-C4.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-C4.t	Wed May 31 14:28:14 2017 +0200
@@ -87,7 +87,7 @@
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 a9c02d134f5b98acc74d1dc4eb28fd59f958a2bd
   f5bc6836db60e308a17ba08bf050154ba9c4fad7 619b4d13bd9878f04d7208dcfcf1e89da826f6be
   35b1839966785d5703a01607229eea932db42f87 ddeb7b7a87378f59cecb36d5146df0092b6b3327
-  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 58ef2e726c5bd89bceffb6243294b38eadbf3d60
+  7f7f229b13a629a5b20581c6cb723f4e2ca54bed 0ef78fef48a60c677f55ba6efa4126dab2d6caf2
   obshashrange
   ============
            rev         node        index         size        depth      obshash
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-metaedit.t	Wed May 31 14:28:14 2017 +0200
@@ -0,0 +1,215 @@
+  $ cat >> $HGRCPATH <<EOF
+  > [defaults]
+  > amend=-d "0 0"
+  > fold=-d "0 0"
+  > metaedit=-d "0 0"
+  > [web]
+  > push_ssl = false
+  > allow_push = *
+  > [phases]
+  > publish = False
+  > [alias]
+  > qlog = log --template='{rev} - {node|short} {desc} ({phase})\n'
+  > [diff]
+  > git = 1
+  > unified = 0
+  > [extensions]
+  > hgext.graphlog=
+  > EOF
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "$1"
+  > }
+
+  $ mkstack() {
+  >    # Creates a stack of commit based on $1 with messages from $2, $3 ..
+  >    hg update $1 -C
+  >    shift
+  >    mkcommits $*
+  > }
+
+  $ glog() {
+  >   hg glog --template '{rev}:{node|short}@{branch}({phase}) {desc|firstline}\n' "$@"
+  > }
+
+  $ shaof() {
+  >   hg log -T {node} -r "first(desc($1))"
+  > }
+
+  $ mkcommits() {
+  >   for i in $@; do mkcommit $i ; done
+  > }
+
+##########################
+importing Parren test
+##########################
+
+  $ cat << EOF >> $HGRCPATH
+  > [ui]
+  > logtemplate = "{rev}\t{bookmarks}: {desc|firstline} - {author|user}\n"
+  > EOF
+
+HG METAEDIT
+===============================
+
+Setup the Base Repo
+-------------------
+
+We start with a plain base repo::
+
+  $ hg init $TESTTMP/metaedit; cd $TESTTMP/metaedit
+  $ mkcommit "ROOT"
+  $ hg phase --public "desc(ROOT)"
+  $ mkcommit "A"
+  $ mkcommit "B"
+  $ hg up "desc(A)"
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ mkcommit "C"
+  created new head
+  $ mkcommit "D"
+  $ echo "D'" > D
+  $ hg amend -m "D2"
+  $ hg up "desc(C)"
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ mkcommit "E"
+  created new head
+  $ mkcommit "F"
+
+Test
+----
+
+  $ hg log -G
+  @  8	: F - test
+  |
+  o  7	: E - test
+  |
+  | o  6	: D2 - test
+  |/
+  o  3	: C - test
+  |
+  | o  2	: B - test
+  |/
+  o  1	: A - test
+  |
+  o  0	: ROOT - test
+  
+  $ hg update --clean .
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg metaedit -r 0
+  abort: cannot edit commit information for public revisions
+  [255]
+  $ hg metaedit --fold
+  abort: revisions must be specified with --fold
+  [255]
+  $ hg metaedit -r 0 --fold
+  abort: cannot fold public revisions
+  [255]
+  $ hg metaedit 'desc(C) + desc(F)' --fold
+  abort: cannot fold non-linear revisions (multiple roots given)
+  [255]
+  $ hg metaedit "desc(C)::desc(D2) + desc(E)" --fold
+  abort: cannot fold non-linear revisions (multiple heads given)
+  [255]
+check that metaedit respects allowunstable
+  $ hg metaedit '.^' --config 'experimental.evolution=createmarkers, allnewcommands'
+  abort: cannot edit commit information in the middle of a stack
+  (587528abfffe will become unstable and new unstable changes are not allowed)
+  [255]
+  $ hg metaedit 'desc(A)::desc(B)' --fold --config 'experimental.evolution=createmarkers, allnewcommands'
+  abort: cannot fold chain not ending with a head or with branching
+  (new unstable changesets are not allowed)
+  [255]
+  $ hg metaedit --user foobar
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log --template '{rev}: {author}\n' -r 'desc(F):' --hidden
+  5: test
+  6: test
+  7: test
+  8: test
+  9: foobar
+  $ hg log --template '{rev}: {author}\n' -r .
+  9: foobar
+
+TODO: support this
+  $ hg metaedit '.^::.'
+  abort: editing multiple revisions without --fold is not currently supported
+  [255]
+
+  $ HGEDITOR=cat hg metaedit '.^::.' --fold
+  HG: This is a fold of 2 changesets.
+  HG: Commit message of changeset 7.
+  
+  E
+  
+  HG: Commit message of changeset 9.
+  
+  F
+  
+  
+  
+  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
+  HG: Leave message empty to abort commit.
+  HG: --
+  HG: user: test
+  HG: branch 'default'
+  HG: added E
+  HG: added F
+  2 changesets folded
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ glog -r .
+  @  10:a08d35fd7d9d@default(draft) E
+  |
+  ~
+
+no new commit is created here because the date is the same
+  $ HGEDITOR=cat hg metaedit
+  E
+  
+  
+  F
+  
+  
+  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
+  HG: Leave message empty to abort commit.
+  HG: --
+  HG: user: test
+  HG: branch 'default'
+  HG: added E
+  HG: added F
+  nothing changed
+
+  $ glog -r '.^::.'
+  @  10:a08d35fd7d9d@default(draft) E
+  |
+  o  3:3260958f1169@default(draft) C
+  |
+  ~
+
+TODO: don't create a new commit in this case, we should take the date of the
+old commit (we add a default date with a value to show that metaedit is taking
+the current date to generate the hash, this way we still have a stable hash
+but highlight the bug)
+  $ hg metaedit --config defaults.metaedit= --config devel.default-date="42 0"
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log -r '.^::.' --template '{rev}: {desc|firstline}\n'
+  3: C
+  11: E
+
+  $ hg up .^
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ hg metaedit --user foobar2 tip
+  $ hg log --template '{rev}: {author}\n' -r "user(foobar):" --hidden
+  9: foobar
+  10: test
+  11: test
+  12: foobar2
+  $ hg diff -r "10" -r "11" --hidden
+
+'fold' one commit
+  $ hg metaedit "desc(D2)" --fold --user foobar3
+  1 changesets folded
+  $ hg log -r "tip" --template '{rev}: {author}\n'
+  13: foobar3
--- a/tests/test-obsolete-push.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-obsolete-push.t	Wed May 31 14:28:14 2017 +0200
@@ -56,7 +56,7 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
-  1 new obsolescence markers
+  2 new obsolescence markers
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd strict-publish-client
--- a/tests/test-prune.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-prune.t	Wed May 31 14:28:14 2017 +0200
@@ -355,6 +355,17 @@
       more than 2 successors:         0
       available  keys:
                  user:                7
+  marker size:
+      format v1:
+          smallest length:           69
+          longer length:             69
+          median length:             69
+          mean length:               69
+      format v0:
+          smallest length:          * (glob)
+          longer length:            * (glob)
+          median length:            * (glob)
+          mean length:              * (glob)
   disconnected clusters:              7
           any known node:             7
           smallest length:            1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-stablesort-criss-cross.t	Wed May 31 14:28:14 2017 +0200
@@ -0,0 +1,720 @@
+Test for stable ordering capabilities
+=====================================
+
+  $ . $TESTDIR/testlib/pythonpath.sh
+
+  $ cat << EOF >> $HGRCPATH
+  > [extensions]
+  > hgext3rd.evolve =
+  > [ui]
+  > logtemplate = "{rev} {node|short} {desc} {tags}\n"
+  > [alias]
+  > showsort = debugstablesort --template="{node|short}\n"
+  > EOF
+
+  $ checktopo () {
+  >     seen='null';
+  >     for node in `hg showsort --rev "$1"`; do
+  >         echo "=== checking $node ===";
+  >         hg log --rev "($seen) and $node::";
+  >         seen="${seen}+${node}";
+  >     done;
+  > }
+
+  $ cat << EOF >> random_rev.py
+  > import random
+  > import sys
+  > 
+  > loop = int(sys.argv[1])
+  > var = int(sys.argv[2])
+  > for x in range(loop):
+  >     print(x + random.randint(0, var))
+  > EOF
+
+Check criss cross merge
+=======================
+
+  $ hg init crisscross_A
+  $ cd crisscross_A
+  $ hg debugbuilddag '
+  > ...:base         # create some base
+  > # criss cross #1: simple
+  > +3:AbaseA      # "A" branch for CC "A"
+  > <base+2:AbaseB # "B" branch for CC "B"
+  > <AbaseA/AbaseB:AmergeA
+  > <AbaseB/AbaseA:AmergeB
+  > <AmergeA/AmergeB:Afinal
+  > # criss cross #2:multiple closes ones
+  > .:BbaseA
+  > <AmergeB:BbaseB
+  > <BbaseA/BbaseB:BmergeA
+  > <BbaseB/BbaseA:BmergeB
+  > <BmergeA/BmergeB:BmergeC
+  > <BmergeB/BmergeA:BmergeD
+  > <BmergeC/BmergeD:Bfinal
+  > # criss cross #2:many branches
+  > <Bfinal.:CbaseA
+  > <Bfinal+2:CbaseB
+  > <Bfinal.:CbaseC
+  > <Bfinal+5:CbaseD
+  > <Bfinal.:CbaseE
+  > <CbaseA/CbaseB+7:CmergeA
+  > <CbaseA/CbaseC:CmergeB
+  > <CbaseA/CbaseD.:CmergeC
+  > <CbaseA/CbaseE:CmergeD
+  > <CbaseB/CbaseA+2:CmergeE
+  > <CbaseB/CbaseC:CmergeF
+  > <CbaseB/CbaseD.:CmergeG
+  > <CbaseB/CbaseE:CmergeH
+  > <CbaseC/CbaseA.:CmergeI
+  > <CbaseC/CbaseB:CmergeJ
+  > <CbaseC/CbaseD+5:CmergeK
+  > <CbaseC/CbaseE+2:CmergeL
+  > <CbaseD/CbaseA:CmergeM
+  > <CbaseD/CbaseB...:CmergeN
+  > <CbaseD/CbaseC:CmergeO
+  > <CbaseD/CbaseE:CmergeP
+  > <CbaseE/CbaseA:CmergeQ
+  > <CbaseE/CbaseB..:CmergeR
+  > <CbaseE/CbaseC.:CmergeS
+  > <CbaseE/CbaseD:CmergeT
+  > <CmergeA/CmergeG:CmergeWA
+  > <CmergeB/CmergeF:CmergeWB
+  > <CmergeC/CmergeE:CmergeWC
+  > <CmergeD/CmergeH:CmergeWD
+  > <CmergeT/CmergeI:CmergeWE
+  > <CmergeS/CmergeJ:CmergeWF
+  > <CmergeR/CmergeK:CmergeWG
+  > <CmergeQ/CmergeL:CmergeWH
+  > <CmergeP/CmergeM:CmergeWI
+  > <CmergeO/CmergeN:CmergeWJ
+  > <CmergeO/CmergeN:CmergeWK
+  > <CmergeWA/CmergeWG:CmergeXA
+  > <CmergeWB/CmergeWH:CmergeXB
+  > <CmergeWC/CmergeWI:CmergeXC
+  > <CmergeWD/CmergeWJ:CmergeXD
+  > <CmergeWE/CmergeWK:CmergeXE
+  > <CmergeWF/CmergeWA:CmergeXF
+  > <CmergeXA/CmergeXF:CmergeYA
+  > <CmergeXB/CmergeXE:CmergeYB
+  > <CmergeXC/CmergeXD:CmergeYC
+  > <CmergeYA/CmergeYB:CmergeZA
+  > <CmergeYC/CmergeYB:CmergeZB
+  > <CmergeZA/CmergeZB:Cfinal
+  > '
+  $ hg log -G
+  o    94 01f771406cab r94 Cfinal tip
+  |\
+  | o    93 84d6ec6a8e21 r93 CmergeZB
+  | |\
+  o | |  92 721ba7c5f4ff r92 CmergeZA
+  |\| |
+  | | o    91 8ae32c3ed670 r91 CmergeYC
+  | | |\
+  | o \ \    90 8b79544bb56d r90 CmergeYB
+  | |\ \ \
+  o \ \ \ \    89 041e1188f5f1 r89 CmergeYA
+  |\ \ \ \ \
+  | o \ \ \ \    88 2472d042ec95 r88 CmergeXF
+  | |\ \ \ \ \
+  | | | | o \ \    87 c7d3029bf731 r87 CmergeXE
+  | | | | |\ \ \
+  | | | | | | | o    86 469c700e9ed8 r86 CmergeXD
+  | | | | | | | |\
+  | | | | | | o \ \    85 28be96b80dc1 r85 CmergeXC
+  | | | | | | |\ \ \
+  | | | o \ \ \ \ \ \    84 dbde319d43a3 r84 CmergeXB
+  | | | |\ \ \ \ \ \ \
+  o | | | | | | | | | |  83 b3cf98c3d587 r83 CmergeXA
+  |\| | | | | | | | | |
+  | | | | | | o | | | |    82 1da228afcf06 r82 CmergeWK
+  | | | | | | |\ \ \ \ \
+  | | | | | | +-+-------o  81 0bab31f71a21 r81 CmergeWJ
+  | | | | | | | | | | |
+  | | | | | | | | | o |    80 cd345198cf12 r80 CmergeWI
+  | | | | | | | | | |\ \
+  | | | | o \ \ \ \ \ \ \    79 82238c0bc950 r79 CmergeWH
+  | | | | |\ \ \ \ \ \ \ \
+  o \ \ \ \ \ \ \ \ \ \ \ \    78 89a0fe204177 r78 CmergeWG
+  |\ \ \ \ \ \ \ \ \ \ \ \ \
+  | | | o \ \ \ \ \ \ \ \ \ \    77 97d19fc5236f r77 CmergeWF
+  | | | |\ \ \ \ \ \ \ \ \ \ \
+  | | | | | | | | o \ \ \ \ \ \    76 37ad3ab0cddf r76 CmergeWE
+  | | | | | | | | |\ \ \ \ \ \ \
+  | | | | | | | | | | | | | | | o    75 790cdfecd168 r75 CmergeWD
+  | | | | | | | | | | | | | | | |\
+  | | | | | | | | | | | | o \ \ \ \    74 698970a2480b r74 CmergeWC
+  | | | | | | | | | | | | |\ \ \ \ \
+  | | | | | o \ \ \ \ \ \ \ \ \ \ \ \    73 31d7b43cc321 r73 CmergeWB
+  | | | | | |\ \ \ \ \ \ \ \ \ \ \ \ \
+  | | o \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \    72 eed373b0090d r72 CmergeWA
+  | | |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
+  | | | | | | | | | | | o \ \ \ \ \ \ \ \    71 4f3b41956174 r71 CmergeT
+  | | | | | | | | | | | |\ \ \ \ \ \ \ \ \
+  | | | | | o | | | | | | | | | | | | | | |  70 c3c7fa726f88 r70 CmergeS
+  | | | | | | | | | | | | | | | | | | | | |
+  | | | | | o-------------+ | | | | | | | |  69 d917f77a6439 r69
+  | | | | | | | | | | | | | | | | | | | | |
+  | o | | | | | | | | | | | | | | | | | | |  68 fac9e582edd1 r68 CmergeR
+  | | | | | | | | | | | | | | | | | | | | |
+  | o | | | | | | | | | | | | | | | | | | |  67 e4cfd6264623 r67
+  | | | | | | | | | | | | | | | | | | | | |
+  | o---------------------+ | | | | | | | |  66 d99e0f7dad5b r66
+  | | | | | | | | | | | | | | | | | | | | |
+  | | | | | | | | | o-----+ | | | | | | | |  65 c713eae2d31f r65 CmergeQ
+  | | | | | | | | | | | | | | | | | | | | |
+  | | | | | | | | | | | +-+-----------o | |  64 b33fd5ad4c0c r64 CmergeP
+  | | | | | | | | | | | | | | | | | |  / /
+  | | | | | +-----------+-----o | | | / /  63 bf6593f7e073 r63 CmergeO
+  | | | | | | | | | | | | | |  / / / / /
+  | | | | | | | | | | | | | o | | | | |  62 3871506da61e r62 CmergeN
+  | | | | | | | | | | | | | | | | | | |
+  | | | | | | | | | | | | | o | | | | |  61 c84da74cf586 r61
+  | | | | | | | | | | | | | | | | | | |
+  | | | | | | | | | | | | | o | | | | |  60 5eec91b12a58 r60
+  | | | | | | | | | | | | | | | | | | |
+  | +-------------------+---o | | | | |  59 0484d39906c8 r59
+  | | | | | | | | | | | | |  / / / / /
+  | | | | | | | | | +---+-------o / /  58 29141354a762 r58 CmergeM
+  | | | | | | | | | | | | | | |  / /
+  | | | | | | | | o | | | | | | | |  57 e7135b665740 r57 CmergeL
+  | | | | | | | | | | | | | | | | |
+  | | | | | | | | o | | | | | | | |  56 c7c1497fc270 r56
+  | | | | | | | | | | | | | | | | |
+  | | | | | +-----o-------+ | | | |  55 76151e8066e1 r55
+  | | | | | | | |  / / / / / / / /
+  o | | | | | | | | | | | | | | |  54 9a67238ad1c4 r54 CmergeK
+  | | | | | | | | | | | | | | | |
+  o | | | | | | | | | | | | | | |  53 c37e7cd9f2bd r53
+  | | | | | | | | | | | | | | | |
+  o | | | | | | | | | | | | | | |  52 0d153e3ad632 r52
+  | | | | | | | | | | | | | | | |
+  o | | | | | | | | | | | | | | |  51 97ac964e34b7 r51
+  | | | | | | | | | | | | | | | |
+  o | | | | | | | | | | | | | | |  50 900dd066a072 r50
+  | | | | | | | | | | | | | | | |
+  o---------+---------+ | | | | |  49 673f5499c8c2 r49
+   / / / / / / / / / / / / / / /
+  +-----o / / / / / / / / / / /  48 8ecb28746ec4 r48 CmergeJ
+  | | | |/ / / / / / / / / / /
+  | | | | | | | o | | | | | |  47 d6c9e2d27f14 r47 CmergeI
+  | | | | | | | | | | | | | |
+  | | | +-------o | | | | | |  46 bfcfd9a61e84 r46
+  | | | | | | |/ / / / / / /
+  +---------------+-------o  45 40553f55397e r45 CmergeH
+  | | | | | | | | | | | |
+  | | o | | | | | | | | |  44 d94da36be176 r44 CmergeG
+  | | | | | | | | | | | |
+  +---o---------+ | | | |  43 4b39f229a0ce r43
+  | |  / / / / / / / / /
+  +---+---o / / / / / /  42 43fc0b77ff07 r42 CmergeF
+  | | | |  / / / / / /
+  | | | | | | | | o |  41 88eace5ce682 r41 CmergeE
+  | | | | | | | | | |
+  | | | | | | | | o |  40 d928b4e8a515 r40
+  | | | | | | | | | |
+  +-------+-------o |  39 88714f4125cb r39
+  | | | | | | | |  /
+  | | | | +---+---o  38 e3e6738c56ce r38 CmergeD
+  | | | | | | | |
+  | | | | | | | o  37 32b41ca704e1 r37 CmergeC
+  | | | | | | | |
+  | | | | +-+---o  36 01e29e20ea3f r36
+  | | | | | | |
+  | | | o | | |  35 1f4a19f83a29 r35 CmergeB
+  | | |/|/ / /
+  | o | | | |  34 722d1b8b8942 r34 CmergeA
+  | | | | | |
+  | o | | | |  33 47c836a1f13e r33
+  | | | | | |
+  | o | | | |  32 2ea3fbf151b5 r32
+  | | | | | |
+  | o | | | |  31 0c3f2ba59eb7 r31
+  | | | | | |
+  | o | | | |  30 f3441cd3e664 r30
+  | | | | | |
+  | o | | | |  29 b9c3aa92fba5 r29
+  | | | | | |
+  | o | | | |  28 3bdb00d5c818 r28
+  | | | | | |
+  | o---+ | |  27 2bd677d0f13a r27
+  |/ / / / /
+  | | | | o  26 de05b9c29ec7 r26 CbaseE
+  | | | | |
+  | | | o |  25 ad46a4a0fc10 r25 CbaseD
+  | | | | |
+  | | | o |  24 a457569c5306 r24
+  | | | | |
+  | | | o |  23 f2bdd828a3aa r23
+  | | | | |
+  | | | o |  22 5ce588c2b7c5 r22
+  | | | | |
+  | | | o |  21 17b6e6bac221 r21
+  | | | |/
+  | o---+  20 b115c694654e r20 CbaseC
+  |  / /
+  o | |  19 884936b34999 r19 CbaseB
+  | | |
+  o---+  18 9729470d9329 r18
+   / /
+  o /  17 4f5078f7da8a r17 CbaseA
+  |/
+  o    16 3e1560705803 r16 Bfinal
+  |\
+  | o    15 55bf3fdb634f r15 BmergeD
+  | |\
+  o---+  14 39bab1cb1cbe r14 BmergeC
+  |/ /
+  | o    13 f7c6e7bfbcd0 r13 BmergeB
+  | |\
+  o---+  12 26f59ee8b1d7 r12 BmergeA
+  |/ /
+  | o  11 3e2da24aee59 r11 BbaseA
+  | |
+  | o  10 5ba9a53052ed r10 Afinal
+  |/|
+  o |    9 07c648efceeb r9 AmergeB BbaseB
+  |\ \
+  +---o  8 c81423bf5a24 r8 AmergeA
+  | |/
+  | o  7 65eb34ffc3a8 r7 AbaseB
+  | |
+  | o  6 0c1445abb33d r6
+  | |
+  o |  5 c8d03c1b5e94 r5 AbaseA
+  | |
+  o |  4 bebd167eb94d r4
+  | |
+  o |  3 2dc09a01254d r3
+  |/
+  o  2 01241442b3c2 r2 base
+  |
+  o  1 66f7d451a68b r1
+  |
+  o  0 1ea73414a91b r0
+  
+
+Basic check
+-----------
+
+  $ hg showsort --rev 'Afinal'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  07c648efceeb
+  c81423bf5a24
+  5ba9a53052ed
+  $ checktopo Afinal
+  === checking 1ea73414a91b ===
+  === checking 66f7d451a68b ===
+  === checking 01241442b3c2 ===
+  === checking 0c1445abb33d ===
+  === checking 65eb34ffc3a8 ===
+  === checking 2dc09a01254d ===
+  === checking bebd167eb94d ===
+  === checking c8d03c1b5e94 ===
+  === checking 07c648efceeb ===
+  === checking c81423bf5a24 ===
+  === checking 5ba9a53052ed ===
+  $ hg showsort --rev 'AmergeA'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  c81423bf5a24
+  $ checktopo AmergeA
+  === checking 1ea73414a91b ===
+  === checking 66f7d451a68b ===
+  === checking 01241442b3c2 ===
+  === checking 0c1445abb33d ===
+  === checking 65eb34ffc3a8 ===
+  === checking 2dc09a01254d ===
+  === checking bebd167eb94d ===
+  === checking c8d03c1b5e94 ===
+  === checking c81423bf5a24 ===
+  $ hg showsort --rev 'AmergeB'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  07c648efceeb
+  $ checktopo AmergeB
+  === checking 1ea73414a91b ===
+  === checking 66f7d451a68b ===
+  === checking 01241442b3c2 ===
+  === checking 0c1445abb33d ===
+  === checking 65eb34ffc3a8 ===
+  === checking 2dc09a01254d ===
+  === checking bebd167eb94d ===
+  === checking c8d03c1b5e94 ===
+  === checking 07c648efceeb ===
+
+close criss cross
+  $ hg showsort --rev 'Bfinal'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  07c648efceeb
+  c81423bf5a24
+  5ba9a53052ed
+  3e2da24aee59
+  26f59ee8b1d7
+  f7c6e7bfbcd0
+  39bab1cb1cbe
+  55bf3fdb634f
+  3e1560705803
+  $ checktopo Bfinal
+  === checking 1ea73414a91b ===
+  === checking 66f7d451a68b ===
+  === checking 01241442b3c2 ===
+  === checking 0c1445abb33d ===
+  === checking 65eb34ffc3a8 ===
+  === checking 2dc09a01254d ===
+  === checking bebd167eb94d ===
+  === checking c8d03c1b5e94 ===
+  === checking 07c648efceeb ===
+  === checking c81423bf5a24 ===
+  === checking 5ba9a53052ed ===
+  === checking 3e2da24aee59 ===
+  === checking 26f59ee8b1d7 ===
+  === checking f7c6e7bfbcd0 ===
+  === checking 39bab1cb1cbe ===
+  === checking 55bf3fdb634f ===
+  === checking 3e1560705803 ===
+
+many branches criss cross
+
+  $ hg showsort --rev 'Cfinal'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  07c648efceeb
+  c81423bf5a24
+  5ba9a53052ed
+  3e2da24aee59
+  26f59ee8b1d7
+  f7c6e7bfbcd0
+  39bab1cb1cbe
+  55bf3fdb634f
+  3e1560705803
+  17b6e6bac221
+  5ce588c2b7c5
+  f2bdd828a3aa
+  a457569c5306
+  ad46a4a0fc10
+  4f5078f7da8a
+  01e29e20ea3f
+  32b41ca704e1
+  29141354a762
+  9729470d9329
+  884936b34999
+  0484d39906c8
+  5eec91b12a58
+  c84da74cf586
+  3871506da61e
+  2bd677d0f13a
+  3bdb00d5c818
+  b9c3aa92fba5
+  f3441cd3e664
+  0c3f2ba59eb7
+  2ea3fbf151b5
+  47c836a1f13e
+  722d1b8b8942
+  4b39f229a0ce
+  d94da36be176
+  eed373b0090d
+  88714f4125cb
+  d928b4e8a515
+  88eace5ce682
+  698970a2480b
+  b115c694654e
+  1f4a19f83a29
+  43fc0b77ff07
+  31d7b43cc321
+  673f5499c8c2
+  900dd066a072
+  97ac964e34b7
+  0d153e3ad632
+  c37e7cd9f2bd
+  9a67238ad1c4
+  8ecb28746ec4
+  bf6593f7e073
+  0bab31f71a21
+  1da228afcf06
+  bfcfd9a61e84
+  d6c9e2d27f14
+  de05b9c29ec7
+  40553f55397e
+  4f3b41956174
+  37ad3ab0cddf
+  c7d3029bf731
+  76151e8066e1
+  c7c1497fc270
+  e7135b665740
+  b33fd5ad4c0c
+  cd345198cf12
+  28be96b80dc1
+  c713eae2d31f
+  82238c0bc950
+  dbde319d43a3
+  8b79544bb56d
+  d917f77a6439
+  c3c7fa726f88
+  97d19fc5236f
+  2472d042ec95
+  d99e0f7dad5b
+  e4cfd6264623
+  fac9e582edd1
+  89a0fe204177
+  b3cf98c3d587
+  041e1188f5f1
+  721ba7c5f4ff
+  e3e6738c56ce
+  790cdfecd168
+  469c700e9ed8
+  8ae32c3ed670
+  84d6ec6a8e21
+  01f771406cab
+  $ checktopo Cfinal
+  === checking 1ea73414a91b ===
+  === checking 66f7d451a68b ===
+  === checking 01241442b3c2 ===
+  === checking 0c1445abb33d ===
+  === checking 65eb34ffc3a8 ===
+  === checking 2dc09a01254d ===
+  === checking bebd167eb94d ===
+  === checking c8d03c1b5e94 ===
+  === checking 07c648efceeb ===
+  === checking c81423bf5a24 ===
+  === checking 5ba9a53052ed ===
+  === checking 3e2da24aee59 ===
+  === checking 26f59ee8b1d7 ===
+  === checking f7c6e7bfbcd0 ===
+  === checking 39bab1cb1cbe ===
+  === checking 55bf3fdb634f ===
+  === checking 3e1560705803 ===
+  === checking 17b6e6bac221 ===
+  === checking 5ce588c2b7c5 ===
+  === checking f2bdd828a3aa ===
+  === checking a457569c5306 ===
+  === checking ad46a4a0fc10 ===
+  === checking 4f5078f7da8a ===
+  === checking 01e29e20ea3f ===
+  === checking 32b41ca704e1 ===
+  === checking 29141354a762 ===
+  === checking 9729470d9329 ===
+  === checking 884936b34999 ===
+  === checking 0484d39906c8 ===
+  === checking 5eec91b12a58 ===
+  === checking c84da74cf586 ===
+  === checking 3871506da61e ===
+  === checking 2bd677d0f13a ===
+  === checking 3bdb00d5c818 ===
+  === checking b9c3aa92fba5 ===
+  === checking f3441cd3e664 ===
+  === checking 0c3f2ba59eb7 ===
+  === checking 2ea3fbf151b5 ===
+  === checking 47c836a1f13e ===
+  === checking 722d1b8b8942 ===
+  === checking 4b39f229a0ce ===
+  === checking d94da36be176 ===
+  === checking eed373b0090d ===
+  === checking 88714f4125cb ===
+  === checking d928b4e8a515 ===
+  === checking 88eace5ce682 ===
+  === checking 698970a2480b ===
+  === checking b115c694654e ===
+  === checking 1f4a19f83a29 ===
+  === checking 43fc0b77ff07 ===
+  === checking 31d7b43cc321 ===
+  === checking 673f5499c8c2 ===
+  === checking 900dd066a072 ===
+  === checking 97ac964e34b7 ===
+  === checking 0d153e3ad632 ===
+  === checking c37e7cd9f2bd ===
+  === checking 9a67238ad1c4 ===
+  === checking 8ecb28746ec4 ===
+  === checking bf6593f7e073 ===
+  === checking 0bab31f71a21 ===
+  === checking 1da228afcf06 ===
+  === checking bfcfd9a61e84 ===
+  === checking d6c9e2d27f14 ===
+  === checking de05b9c29ec7 ===
+  === checking 40553f55397e ===
+  === checking 4f3b41956174 ===
+  === checking 37ad3ab0cddf ===
+  === checking c7d3029bf731 ===
+  === checking 76151e8066e1 ===
+  === checking c7c1497fc270 ===
+  === checking e7135b665740 ===
+  === checking b33fd5ad4c0c ===
+  === checking cd345198cf12 ===
+  === checking 28be96b80dc1 ===
+  === checking c713eae2d31f ===
+  === checking 82238c0bc950 ===
+  === checking dbde319d43a3 ===
+  === checking 8b79544bb56d ===
+  === checking d917f77a6439 ===
+  === checking c3c7fa726f88 ===
+  === checking 97d19fc5236f ===
+  === checking 2472d042ec95 ===
+  === checking d99e0f7dad5b ===
+  === checking e4cfd6264623 ===
+  === checking fac9e582edd1 ===
+  === checking 89a0fe204177 ===
+  === checking b3cf98c3d587 ===
+  === checking 041e1188f5f1 ===
+  === checking 721ba7c5f4ff ===
+  === checking e3e6738c56ce ===
+  === checking 790cdfecd168 ===
+  === checking 469c700e9ed8 ===
+  === checking 8ae32c3ed670 ===
+  === checking 84d6ec6a8e21 ===
+  === checking 01f771406cab ===
+
+Test stability of this mess
+---------------------------
+
+  $ hg log -r tip
+  94 01f771406cab r94 Cfinal tip
+  $ hg showsort --rev 'all()' > ../crisscross.source.order
+  $ cd ..
+
+  $ hg clone crisscross_A crisscross_random --rev 0
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 0 changes to 0 files
+  updating to branch default
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd crisscross_random
+  $ for x in `python ../random_rev.py 50 44`; do
+  >   # using python to benefit from the random seed
+  >   hg pull -r $x --quiet
+  > done;
+  $ hg pull --quiet
+
+  $ hg showsort --rev 'all()' > ../crisscross.random.order
+  $ python "$RUNTESTDIR/md5sum.py" ../crisscross.*.order
+  d9aab0d1907d5cf64d205a8b9036e959  ../crisscross.random.order
+  d9aab0d1907d5cf64d205a8b9036e959  ../crisscross.source.order
+  $ diff -u ../crisscross.*.order
+  $ hg showsort --rev 'all()'
+  1ea73414a91b
+  66f7d451a68b
+  01241442b3c2
+  0c1445abb33d
+  65eb34ffc3a8
+  2dc09a01254d
+  bebd167eb94d
+  c8d03c1b5e94
+  07c648efceeb
+  c81423bf5a24
+  5ba9a53052ed
+  3e2da24aee59
+  26f59ee8b1d7
+  f7c6e7bfbcd0
+  39bab1cb1cbe
+  55bf3fdb634f
+  3e1560705803
+  17b6e6bac221
+  5ce588c2b7c5
+  f2bdd828a3aa
+  a457569c5306
+  ad46a4a0fc10
+  4f5078f7da8a
+  01e29e20ea3f
+  32b41ca704e1
+  29141354a762
+  9729470d9329
+  884936b34999
+  0484d39906c8
+  5eec91b12a58
+  c84da74cf586
+  3871506da61e
+  2bd677d0f13a
+  3bdb00d5c818
+  b9c3aa92fba5
+  f3441cd3e664
+  0c3f2ba59eb7
+  2ea3fbf151b5
+  47c836a1f13e
+  722d1b8b8942
+  4b39f229a0ce
+  d94da36be176
+  eed373b0090d
+  88714f4125cb
+  d928b4e8a515
+  88eace5ce682
+  698970a2480b
+  b115c694654e
+  1f4a19f83a29
+  43fc0b77ff07
+  31d7b43cc321
+  673f5499c8c2
+  900dd066a072
+  97ac964e34b7
+  0d153e3ad632
+  c37e7cd9f2bd
+  9a67238ad1c4
+  8ecb28746ec4
+  bf6593f7e073
+  0bab31f71a21
+  1da228afcf06
+  bfcfd9a61e84
+  d6c9e2d27f14
+  de05b9c29ec7
+  40553f55397e
+  4f3b41956174
+  37ad3ab0cddf
+  c7d3029bf731
+  76151e8066e1
+  c7c1497fc270
+  e7135b665740
+  b33fd5ad4c0c
+  cd345198cf12
+  28be96b80dc1
+  c713eae2d31f
+  82238c0bc950
+  dbde319d43a3
+  8b79544bb56d
+  d917f77a6439
+  c3c7fa726f88
+  97d19fc5236f
+  2472d042ec95
+  d99e0f7dad5b
+  e4cfd6264623
+  fac9e582edd1
+  89a0fe204177
+  b3cf98c3d587
+  041e1188f5f1
+  721ba7c5f4ff
+  e3e6738c56ce
+  790cdfecd168
+  469c700e9ed8
+  8ae32c3ed670
+  84d6ec6a8e21
+  01f771406cab
--- a/tests/test-stablesort.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-stablesort.t	Wed May 31 14:28:14 2017 +0200
@@ -23,6 +23,16 @@
   >     done;
   > }
 
+  $ cat << EOF >> random_rev.py
+  > import random
+  > import sys
+  > 
+  > loop = int(sys.argv[1])
+  > var = int(sys.argv[2])
+  > for x in range(loop):
+  >     print(x + random.randint(0, var))
+  > EOF
+
 Basic tests
 ===========
 (no criss cross merge)
@@ -468,16 +478,6 @@
 Multiple recursions
 ===================
 
-  $ cat << EOF >> random_rev.py
-  > import random
-  > import sys
-  > 
-  > loop = int(sys.argv[1])
-  > var = int(sys.argv[2])
-  > for x in range(loop):
-  >     print(x + random.randint(0, var))
-  > EOF
-
   $ hg init recursion_A
   $ cd recursion_A
   $ hg debugbuilddag '
@@ -624,694 +624,6 @@
   4bbfc6078919
   $ cd ..
 
-Check criss cross merge
-=======================
-
-  $ hg init crisscross_A
-  $ cd crisscross_A
-  $ hg debugbuilddag '
-  > ...:base         # create some base
-  > # criss cross #1: simple
-  > +3:AbaseA      # "A" branch for CC "A"
-  > <base+2:AbaseB # "B" branch for CC "B"
-  > <AbaseA/AbaseB:AmergeA
-  > <AbaseB/AbaseA:AmergeB
-  > <AmergeA/AmergeB:Afinal
-  > # criss cross #2:multiple closes ones
-  > .:BbaseA
-  > <AmergeB:BbaseB
-  > <BbaseA/BbaseB:BmergeA
-  > <BbaseB/BbaseA:BmergeB
-  > <BmergeA/BmergeB:BmergeC
-  > <BmergeB/BmergeA:BmergeD
-  > <BmergeC/BmergeD:Bfinal
-  > # criss cross #2:many branches
-  > <Bfinal.:CbaseA
-  > <Bfinal+2:CbaseB
-  > <Bfinal.:CbaseC
-  > <Bfinal+5:CbaseD
-  > <Bfinal.:CbaseE
-  > <CbaseA/CbaseB+7:CmergeA
-  > <CbaseA/CbaseC:CmergeB
-  > <CbaseA/CbaseD.:CmergeC
-  > <CbaseA/CbaseE:CmergeD
-  > <CbaseB/CbaseA+2:CmergeE
-  > <CbaseB/CbaseC:CmergeF
-  > <CbaseB/CbaseD.:CmergeG
-  > <CbaseB/CbaseE:CmergeH
-  > <CbaseC/CbaseA.:CmergeI
-  > <CbaseC/CbaseB:CmergeJ
-  > <CbaseC/CbaseD+5:CmergeK
-  > <CbaseC/CbaseE+2:CmergeL
-  > <CbaseD/CbaseA:CmergeM
-  > <CbaseD/CbaseB...:CmergeN
-  > <CbaseD/CbaseC:CmergeO
-  > <CbaseD/CbaseE:CmergeP
-  > <CbaseE/CbaseA:CmergeQ
-  > <CbaseE/CbaseB..:CmergeR
-  > <CbaseE/CbaseC.:CmergeS
-  > <CbaseE/CbaseD:CmergeT
-  > <CmergeA/CmergeG:CmergeWA
-  > <CmergeB/CmergeF:CmergeWB
-  > <CmergeC/CmergeE:CmergeWC
-  > <CmergeD/CmergeH:CmergeWD
-  > <CmergeT/CmergeI:CmergeWE
-  > <CmergeS/CmergeJ:CmergeWF
-  > <CmergeR/CmergeK:CmergeWG
-  > <CmergeQ/CmergeL:CmergeWH
-  > <CmergeP/CmergeM:CmergeWI
-  > <CmergeO/CmergeN:CmergeWJ
-  > <CmergeO/CmergeN:CmergeWK
-  > <CmergeWA/CmergeWG:CmergeXA
-  > <CmergeWB/CmergeWH:CmergeXB
-  > <CmergeWC/CmergeWI:CmergeXC
-  > <CmergeWD/CmergeWJ:CmergeXD
-  > <CmergeWE/CmergeWK:CmergeXE
-  > <CmergeWF/CmergeWA:CmergeXF
-  > <CmergeXA/CmergeXF:CmergeYA
-  > <CmergeXB/CmergeXE:CmergeYB
-  > <CmergeXC/CmergeXD:CmergeYC
-  > <CmergeYA/CmergeYB:CmergeZA
-  > <CmergeYC/CmergeYB:CmergeZB
-  > <CmergeZA/CmergeZB:Cfinal
-  > '
-  $ hg log -G
-  o    94 01f771406cab r94 Cfinal tip
-  |\
-  | o    93 84d6ec6a8e21 r93 CmergeZB
-  | |\
-  o | |  92 721ba7c5f4ff r92 CmergeZA
-  |\| |
-  | | o    91 8ae32c3ed670 r91 CmergeYC
-  | | |\
-  | o \ \    90 8b79544bb56d r90 CmergeYB
-  | |\ \ \
-  o \ \ \ \    89 041e1188f5f1 r89 CmergeYA
-  |\ \ \ \ \
-  | o \ \ \ \    88 2472d042ec95 r88 CmergeXF
-  | |\ \ \ \ \
-  | | | | o \ \    87 c7d3029bf731 r87 CmergeXE
-  | | | | |\ \ \
-  | | | | | | | o    86 469c700e9ed8 r86 CmergeXD
-  | | | | | | | |\
-  | | | | | | o \ \    85 28be96b80dc1 r85 CmergeXC
-  | | | | | | |\ \ \
-  | | | o \ \ \ \ \ \    84 dbde319d43a3 r84 CmergeXB
-  | | | |\ \ \ \ \ \ \
-  o | | | | | | | | | |  83 b3cf98c3d587 r83 CmergeXA
-  |\| | | | | | | | | |
-  | | | | | | o | | | |    82 1da228afcf06 r82 CmergeWK
-  | | | | | | |\ \ \ \ \
-  | | | | | | +-+-------o  81 0bab31f71a21 r81 CmergeWJ
-  | | | | | | | | | | |
-  | | | | | | | | | o |    80 cd345198cf12 r80 CmergeWI
-  | | | | | | | | | |\ \
-  | | | | o \ \ \ \ \ \ \    79 82238c0bc950 r79 CmergeWH
-  | | | | |\ \ \ \ \ \ \ \
-  o \ \ \ \ \ \ \ \ \ \ \ \    78 89a0fe204177 r78 CmergeWG
-  |\ \ \ \ \ \ \ \ \ \ \ \ \
-  | | | o \ \ \ \ \ \ \ \ \ \    77 97d19fc5236f r77 CmergeWF
-  | | | |\ \ \ \ \ \ \ \ \ \ \
-  | | | | | | | | o \ \ \ \ \ \    76 37ad3ab0cddf r76 CmergeWE
-  | | | | | | | | |\ \ \ \ \ \ \
-  | | | | | | | | | | | | | | | o    75 790cdfecd168 r75 CmergeWD
-  | | | | | | | | | | | | | | | |\
-  | | | | | | | | | | | | o \ \ \ \    74 698970a2480b r74 CmergeWC
-  | | | | | | | | | | | | |\ \ \ \ \
-  | | | | | o \ \ \ \ \ \ \ \ \ \ \ \    73 31d7b43cc321 r73 CmergeWB
-  | | | | | |\ \ \ \ \ \ \ \ \ \ \ \ \
-  | | o \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \    72 eed373b0090d r72 CmergeWA
-  | | |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
-  | | | | | | | | | | | o \ \ \ \ \ \ \ \    71 4f3b41956174 r71 CmergeT
-  | | | | | | | | | | | |\ \ \ \ \ \ \ \ \
-  | | | | | o | | | | | | | | | | | | | | |  70 c3c7fa726f88 r70 CmergeS
-  | | | | | | | | | | | | | | | | | | | | |
-  | | | | | o-------------+ | | | | | | | |  69 d917f77a6439 r69
-  | | | | | | | | | | | | | | | | | | | | |
-  | o | | | | | | | | | | | | | | | | | | |  68 fac9e582edd1 r68 CmergeR
-  | | | | | | | | | | | | | | | | | | | | |
-  | o | | | | | | | | | | | | | | | | | | |  67 e4cfd6264623 r67
-  | | | | | | | | | | | | | | | | | | | | |
-  | o---------------------+ | | | | | | | |  66 d99e0f7dad5b r66
-  | | | | | | | | | | | | | | | | | | | | |
-  | | | | | | | | | o-----+ | | | | | | | |  65 c713eae2d31f r65 CmergeQ
-  | | | | | | | | | | | | | | | | | | | | |
-  | | | | | | | | | | | +-+-----------o | |  64 b33fd5ad4c0c r64 CmergeP
-  | | | | | | | | | | | | | | | | | |  / /
-  | | | | | +-----------+-----o | | | / /  63 bf6593f7e073 r63 CmergeO
-  | | | | | | | | | | | | | |  / / / / /
-  | | | | | | | | | | | | | o | | | | |  62 3871506da61e r62 CmergeN
-  | | | | | | | | | | | | | | | | | | |
-  | | | | | | | | | | | | | o | | | | |  61 c84da74cf586 r61
-  | | | | | | | | | | | | | | | | | | |
-  | | | | | | | | | | | | | o | | | | |  60 5eec91b12a58 r60
-  | | | | | | | | | | | | | | | | | | |
-  | +-------------------+---o | | | | |  59 0484d39906c8 r59
-  | | | | | | | | | | | | |  / / / / /
-  | | | | | | | | | +---+-------o / /  58 29141354a762 r58 CmergeM
-  | | | | | | | | | | | | | | |  / /
-  | | | | | | | | o | | | | | | | |  57 e7135b665740 r57 CmergeL
-  | | | | | | | | | | | | | | | | |
-  | | | | | | | | o | | | | | | | |  56 c7c1497fc270 r56
-  | | | | | | | | | | | | | | | | |
-  | | | | | +-----o-------+ | | | |  55 76151e8066e1 r55
-  | | | | | | | |  / / / / / / / /
-  o | | | | | | | | | | | | | | |  54 9a67238ad1c4 r54 CmergeK
-  | | | | | | | | | | | | | | | |
-  o | | | | | | | | | | | | | | |  53 c37e7cd9f2bd r53
-  | | | | | | | | | | | | | | | |
-  o | | | | | | | | | | | | | | |  52 0d153e3ad632 r52
-  | | | | | | | | | | | | | | | |
-  o | | | | | | | | | | | | | | |  51 97ac964e34b7 r51
-  | | | | | | | | | | | | | | | |
-  o | | | | | | | | | | | | | | |  50 900dd066a072 r50
-  | | | | | | | | | | | | | | | |
-  o---------+---------+ | | | | |  49 673f5499c8c2 r49
-   / / / / / / / / / / / / / / /
-  +-----o / / / / / / / / / / /  48 8ecb28746ec4 r48 CmergeJ
-  | | | |/ / / / / / / / / / /
-  | | | | | | | o | | | | | |  47 d6c9e2d27f14 r47 CmergeI
-  | | | | | | | | | | | | | |
-  | | | +-------o | | | | | |  46 bfcfd9a61e84 r46
-  | | | | | | |/ / / / / / /
-  +---------------+-------o  45 40553f55397e r45 CmergeH
-  | | | | | | | | | | | |
-  | | o | | | | | | | | |  44 d94da36be176 r44 CmergeG
-  | | | | | | | | | | | |
-  +---o---------+ | | | |  43 4b39f229a0ce r43
-  | |  / / / / / / / / /
-  +---+---o / / / / / /  42 43fc0b77ff07 r42 CmergeF
-  | | | |  / / / / / /
-  | | | | | | | | o |  41 88eace5ce682 r41 CmergeE
-  | | | | | | | | | |
-  | | | | | | | | o |  40 d928b4e8a515 r40
-  | | | | | | | | | |
-  +-------+-------o |  39 88714f4125cb r39
-  | | | | | | | |  /
-  | | | | +---+---o  38 e3e6738c56ce r38 CmergeD
-  | | | | | | | |
-  | | | | | | | o  37 32b41ca704e1 r37 CmergeC
-  | | | | | | | |
-  | | | | +-+---o  36 01e29e20ea3f r36
-  | | | | | | |
-  | | | o | | |  35 1f4a19f83a29 r35 CmergeB
-  | | |/|/ / /
-  | o | | | |  34 722d1b8b8942 r34 CmergeA
-  | | | | | |
-  | o | | | |  33 47c836a1f13e r33
-  | | | | | |
-  | o | | | |  32 2ea3fbf151b5 r32
-  | | | | | |
-  | o | | | |  31 0c3f2ba59eb7 r31
-  | | | | | |
-  | o | | | |  30 f3441cd3e664 r30
-  | | | | | |
-  | o | | | |  29 b9c3aa92fba5 r29
-  | | | | | |
-  | o | | | |  28 3bdb00d5c818 r28
-  | | | | | |
-  | o---+ | |  27 2bd677d0f13a r27
-  |/ / / / /
-  | | | | o  26 de05b9c29ec7 r26 CbaseE
-  | | | | |
-  | | | o |  25 ad46a4a0fc10 r25 CbaseD
-  | | | | |
-  | | | o |  24 a457569c5306 r24
-  | | | | |
-  | | | o |  23 f2bdd828a3aa r23
-  | | | | |
-  | | | o |  22 5ce588c2b7c5 r22
-  | | | | |
-  | | | o |  21 17b6e6bac221 r21
-  | | | |/
-  | o---+  20 b115c694654e r20 CbaseC
-  |  / /
-  o | |  19 884936b34999 r19 CbaseB
-  | | |
-  o---+  18 9729470d9329 r18
-   / /
-  o /  17 4f5078f7da8a r17 CbaseA
-  |/
-  o    16 3e1560705803 r16 Bfinal
-  |\
-  | o    15 55bf3fdb634f r15 BmergeD
-  | |\
-  o---+  14 39bab1cb1cbe r14 BmergeC
-  |/ /
-  | o    13 f7c6e7bfbcd0 r13 BmergeB
-  | |\
-  o---+  12 26f59ee8b1d7 r12 BmergeA
-  |/ /
-  | o  11 3e2da24aee59 r11 BbaseA
-  | |
-  | o  10 5ba9a53052ed r10 Afinal
-  |/|
-  o |    9 07c648efceeb r9 AmergeB BbaseB
-  |\ \
-  +---o  8 c81423bf5a24 r8 AmergeA
-  | |/
-  | o  7 65eb34ffc3a8 r7 AbaseB
-  | |
-  | o  6 0c1445abb33d r6
-  | |
-  o |  5 c8d03c1b5e94 r5 AbaseA
-  | |
-  o |  4 bebd167eb94d r4
-  | |
-  o |  3 2dc09a01254d r3
-  |/
-  o  2 01241442b3c2 r2 base
-  |
-  o  1 66f7d451a68b r1
-  |
-  o  0 1ea73414a91b r0
-  
-
-Basic check
------------
-
-  $ hg showsort --rev 'Afinal'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  07c648efceeb
-  c81423bf5a24
-  5ba9a53052ed
-  $ checktopo Afinal
-  === checking 1ea73414a91b ===
-  === checking 66f7d451a68b ===
-  === checking 01241442b3c2 ===
-  === checking 0c1445abb33d ===
-  === checking 65eb34ffc3a8 ===
-  === checking 2dc09a01254d ===
-  === checking bebd167eb94d ===
-  === checking c8d03c1b5e94 ===
-  === checking 07c648efceeb ===
-  === checking c81423bf5a24 ===
-  === checking 5ba9a53052ed ===
-  $ hg showsort --rev 'AmergeA'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  c81423bf5a24
-  $ checktopo AmergeA
-  === checking 1ea73414a91b ===
-  === checking 66f7d451a68b ===
-  === checking 01241442b3c2 ===
-  === checking 0c1445abb33d ===
-  === checking 65eb34ffc3a8 ===
-  === checking 2dc09a01254d ===
-  === checking bebd167eb94d ===
-  === checking c8d03c1b5e94 ===
-  === checking c81423bf5a24 ===
-  $ hg showsort --rev 'AmergeB'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  07c648efceeb
-  $ checktopo AmergeB
-  === checking 1ea73414a91b ===
-  === checking 66f7d451a68b ===
-  === checking 01241442b3c2 ===
-  === checking 0c1445abb33d ===
-  === checking 65eb34ffc3a8 ===
-  === checking 2dc09a01254d ===
-  === checking bebd167eb94d ===
-  === checking c8d03c1b5e94 ===
-  === checking 07c648efceeb ===
-
-close criss cross
-  $ hg showsort --rev 'Bfinal'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  07c648efceeb
-  c81423bf5a24
-  5ba9a53052ed
-  3e2da24aee59
-  26f59ee8b1d7
-  f7c6e7bfbcd0
-  39bab1cb1cbe
-  55bf3fdb634f
-  3e1560705803
-  $ checktopo Bfinal
-  === checking 1ea73414a91b ===
-  === checking 66f7d451a68b ===
-  === checking 01241442b3c2 ===
-  === checking 0c1445abb33d ===
-  === checking 65eb34ffc3a8 ===
-  === checking 2dc09a01254d ===
-  === checking bebd167eb94d ===
-  === checking c8d03c1b5e94 ===
-  === checking 07c648efceeb ===
-  === checking c81423bf5a24 ===
-  === checking 5ba9a53052ed ===
-  === checking 3e2da24aee59 ===
-  === checking 26f59ee8b1d7 ===
-  === checking f7c6e7bfbcd0 ===
-  === checking 39bab1cb1cbe ===
-  === checking 55bf3fdb634f ===
-  === checking 3e1560705803 ===
-
-many branches criss cross
-
-  $ hg showsort --rev 'Cfinal'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  07c648efceeb
-  c81423bf5a24
-  5ba9a53052ed
-  3e2da24aee59
-  26f59ee8b1d7
-  f7c6e7bfbcd0
-  39bab1cb1cbe
-  55bf3fdb634f
-  3e1560705803
-  17b6e6bac221
-  5ce588c2b7c5
-  f2bdd828a3aa
-  a457569c5306
-  ad46a4a0fc10
-  4f5078f7da8a
-  01e29e20ea3f
-  32b41ca704e1
-  29141354a762
-  9729470d9329
-  884936b34999
-  0484d39906c8
-  5eec91b12a58
-  c84da74cf586
-  3871506da61e
-  2bd677d0f13a
-  3bdb00d5c818
-  b9c3aa92fba5
-  f3441cd3e664
-  0c3f2ba59eb7
-  2ea3fbf151b5
-  47c836a1f13e
-  722d1b8b8942
-  4b39f229a0ce
-  d94da36be176
-  eed373b0090d
-  88714f4125cb
-  d928b4e8a515
-  88eace5ce682
-  698970a2480b
-  b115c694654e
-  1f4a19f83a29
-  43fc0b77ff07
-  31d7b43cc321
-  673f5499c8c2
-  900dd066a072
-  97ac964e34b7
-  0d153e3ad632
-  c37e7cd9f2bd
-  9a67238ad1c4
-  8ecb28746ec4
-  bf6593f7e073
-  0bab31f71a21
-  1da228afcf06
-  bfcfd9a61e84
-  d6c9e2d27f14
-  de05b9c29ec7
-  40553f55397e
-  4f3b41956174
-  37ad3ab0cddf
-  c7d3029bf731
-  76151e8066e1
-  c7c1497fc270
-  e7135b665740
-  b33fd5ad4c0c
-  cd345198cf12
-  28be96b80dc1
-  c713eae2d31f
-  82238c0bc950
-  dbde319d43a3
-  8b79544bb56d
-  d917f77a6439
-  c3c7fa726f88
-  97d19fc5236f
-  2472d042ec95
-  d99e0f7dad5b
-  e4cfd6264623
-  fac9e582edd1
-  89a0fe204177
-  b3cf98c3d587
-  041e1188f5f1
-  721ba7c5f4ff
-  e3e6738c56ce
-  790cdfecd168
-  469c700e9ed8
-  8ae32c3ed670
-  84d6ec6a8e21
-  01f771406cab
-  $ checktopo Cfinal
-  === checking 1ea73414a91b ===
-  === checking 66f7d451a68b ===
-  === checking 01241442b3c2 ===
-  === checking 0c1445abb33d ===
-  === checking 65eb34ffc3a8 ===
-  === checking 2dc09a01254d ===
-  === checking bebd167eb94d ===
-  === checking c8d03c1b5e94 ===
-  === checking 07c648efceeb ===
-  === checking c81423bf5a24 ===
-  === checking 5ba9a53052ed ===
-  === checking 3e2da24aee59 ===
-  === checking 26f59ee8b1d7 ===
-  === checking f7c6e7bfbcd0 ===
-  === checking 39bab1cb1cbe ===
-  === checking 55bf3fdb634f ===
-  === checking 3e1560705803 ===
-  === checking 17b6e6bac221 ===
-  === checking 5ce588c2b7c5 ===
-  === checking f2bdd828a3aa ===
-  === checking a457569c5306 ===
-  === checking ad46a4a0fc10 ===
-  === checking 4f5078f7da8a ===
-  === checking 01e29e20ea3f ===
-  === checking 32b41ca704e1 ===
-  === checking 29141354a762 ===
-  === checking 9729470d9329 ===
-  === checking 884936b34999 ===
-  === checking 0484d39906c8 ===
-  === checking 5eec91b12a58 ===
-  === checking c84da74cf586 ===
-  === checking 3871506da61e ===
-  === checking 2bd677d0f13a ===
-  === checking 3bdb00d5c818 ===
-  === checking b9c3aa92fba5 ===
-  === checking f3441cd3e664 ===
-  === checking 0c3f2ba59eb7 ===
-  === checking 2ea3fbf151b5 ===
-  === checking 47c836a1f13e ===
-  === checking 722d1b8b8942 ===
-  === checking 4b39f229a0ce ===
-  === checking d94da36be176 ===
-  === checking eed373b0090d ===
-  === checking 88714f4125cb ===
-  === checking d928b4e8a515 ===
-  === checking 88eace5ce682 ===
-  === checking 698970a2480b ===
-  === checking b115c694654e ===
-  === checking 1f4a19f83a29 ===
-  === checking 43fc0b77ff07 ===
-  === checking 31d7b43cc321 ===
-  === checking 673f5499c8c2 ===
-  === checking 900dd066a072 ===
-  === checking 97ac964e34b7 ===
-  === checking 0d153e3ad632 ===
-  === checking c37e7cd9f2bd ===
-  === checking 9a67238ad1c4 ===
-  === checking 8ecb28746ec4 ===
-  === checking bf6593f7e073 ===
-  === checking 0bab31f71a21 ===
-  === checking 1da228afcf06 ===
-  === checking bfcfd9a61e84 ===
-  === checking d6c9e2d27f14 ===
-  === checking de05b9c29ec7 ===
-  === checking 40553f55397e ===
-  === checking 4f3b41956174 ===
-  === checking 37ad3ab0cddf ===
-  === checking c7d3029bf731 ===
-  === checking 76151e8066e1 ===
-  === checking c7c1497fc270 ===
-  === checking e7135b665740 ===
-  === checking b33fd5ad4c0c ===
-  === checking cd345198cf12 ===
-  === checking 28be96b80dc1 ===
-  === checking c713eae2d31f ===
-  === checking 82238c0bc950 ===
-  === checking dbde319d43a3 ===
-  === checking 8b79544bb56d ===
-  === checking d917f77a6439 ===
-  === checking c3c7fa726f88 ===
-  === checking 97d19fc5236f ===
-  === checking 2472d042ec95 ===
-  === checking d99e0f7dad5b ===
-  === checking e4cfd6264623 ===
-  === checking fac9e582edd1 ===
-  === checking 89a0fe204177 ===
-  === checking b3cf98c3d587 ===
-  === checking 041e1188f5f1 ===
-  === checking 721ba7c5f4ff ===
-  === checking e3e6738c56ce ===
-  === checking 790cdfecd168 ===
-  === checking 469c700e9ed8 ===
-  === checking 8ae32c3ed670 ===
-  === checking 84d6ec6a8e21 ===
-  === checking 01f771406cab ===
-
-Test stability of this mess
----------------------------
-
-  $ hg log -r tip
-  94 01f771406cab r94 Cfinal tip
-  $ hg showsort --rev 'all()' > ../crisscross.source.order
-  $ cd ..
-
-  $ hg clone crisscross_A crisscross_random --rev 0
-  adding changesets
-  adding manifests
-  adding file changes
-  added 1 changesets with 0 changes to 0 files
-  updating to branch default
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cd crisscross_random
-  $ for x in `python ../random_rev.py 50 44`; do
-  >   # using python to benefit from the random seed
-  >   hg pull -r $x --quiet
-  > done;
-  $ hg pull --quiet
-
-  $ hg showsort --rev 'all()' > ../crisscross.random.order
-  $ python "$RUNTESTDIR/md5sum.py" ../crisscross.*.order
-  d9aab0d1907d5cf64d205a8b9036e959  ../crisscross.random.order
-  d9aab0d1907d5cf64d205a8b9036e959  ../crisscross.source.order
-  $ diff -u ../crisscross.*.order
-  $ hg showsort --rev 'all()'
-  1ea73414a91b
-  66f7d451a68b
-  01241442b3c2
-  0c1445abb33d
-  65eb34ffc3a8
-  2dc09a01254d
-  bebd167eb94d
-  c8d03c1b5e94
-  07c648efceeb
-  c81423bf5a24
-  5ba9a53052ed
-  3e2da24aee59
-  26f59ee8b1d7
-  f7c6e7bfbcd0
-  39bab1cb1cbe
-  55bf3fdb634f
-  3e1560705803
-  17b6e6bac221
-  5ce588c2b7c5
-  f2bdd828a3aa
-  a457569c5306
-  ad46a4a0fc10
-  4f5078f7da8a
-  01e29e20ea3f
-  32b41ca704e1
-  29141354a762
-  9729470d9329
-  884936b34999
-  0484d39906c8
-  5eec91b12a58
-  c84da74cf586
-  3871506da61e
-  2bd677d0f13a
-  3bdb00d5c818
-  b9c3aa92fba5
-  f3441cd3e664
-  0c3f2ba59eb7
-  2ea3fbf151b5
-  47c836a1f13e
-  722d1b8b8942
-  4b39f229a0ce
-  d94da36be176
-  eed373b0090d
-  88714f4125cb
-  d928b4e8a515
-  88eace5ce682
-  698970a2480b
-  b115c694654e
-  1f4a19f83a29
-  43fc0b77ff07
-  31d7b43cc321
-  673f5499c8c2
-  900dd066a072
-  97ac964e34b7
-  0d153e3ad632
-  c37e7cd9f2bd
-  9a67238ad1c4
-  8ecb28746ec4
-  bf6593f7e073
-  0bab31f71a21
-  1da228afcf06
-  bfcfd9a61e84
-  d6c9e2d27f14
-  de05b9c29ec7
-  40553f55397e
-  4f3b41956174
-  37ad3ab0cddf
-  c7d3029bf731
-  76151e8066e1
-  c7c1497fc270
-  e7135b665740
-  b33fd5ad4c0c
-  cd345198cf12
-  28be96b80dc1
-  c713eae2d31f
-  82238c0bc950
-  dbde319d43a3
-  8b79544bb56d
-  d917f77a6439
-  c3c7fa726f88
-  97d19fc5236f
-  2472d042ec95
-  d99e0f7dad5b
-  e4cfd6264623
-  fac9e582edd1
-  89a0fe204177
-  b3cf98c3d587
-  041e1188f5f1
-  721ba7c5f4ff
-  e3e6738c56ce
-  790cdfecd168
-  469c700e9ed8
-  8ae32c3ed670
-  84d6ec6a8e21
-  01f771406cab
-
 
 Test behavior with oedipus merges
 =================================
--- a/tests/test-wireproto.t	Mon May 22 15:42:13 2017 +0200
+++ b/tests/test-wireproto.t	Wed May 31 14:28:14 2017 +0200
@@ -149,4 +149,34 @@
   1 new obsolescence markers
   (run 'hg heads' to see heads, 'hg merge' to merge)
 
+test discovery avoid exchanging known markers
+
+  $ hg push
+  pushing to ssh://user@dummy/server
+  searching for changes
+  no changes found
+  [1]
+  $ hg -R ../other pull
+  pulling from ssh://user@dummy/server
+  searching for changes
+  no changes found
+
+test discovery can be disabled
+
+  $ hg push --config experimental.evolution.obsdiscovery=no
+  pushing to ssh://user@dummy/server
+  searching for changes
+  (skipping discovery of obsolescence markers, will exchange everything)
+  (controled by 'experimental.evolution.obsdiscovery' configuration)
+  no changes found
+  remote: obsmarker-exchange: 346 bytes received
+  [1]
+  $ hg -R ../other pull --config experimental.evolution.obsdiscovery=no
+  pulling from ssh://user@dummy/server
+  searching for changes
+  no changes found
+  (skipping discovery of obsolescence markers, will exchange everything)
+  (controled by 'experimental.evolution.obsdiscovery' configuration)
+  obsmarker-exchange: 346 bytes received
+
   $ cd ..