merge default into stable stable
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Thu, 05 May 2016 22:13:02 +0200
branchstable
changeset 1695 77df6101d3b5
parent 1674 854421a48e0c (current diff)
parent 1694 5fb7f37b82e6 (diff)
child 1696 898dfca94433
child 1701 4f3601b12c74
merge default into stable Mercurial 3.8 have been release, let's get ready for a 5.4.0 release.
.hgignore
--- a/.hgignore	Wed Apr 20 16:40:11 2016 -0700
+++ b/.hgignore	Thu May 05 22:13:02 2016 +0200
@@ -1,7 +1,5 @@
 syntax: re
 /figures/[^/]+\.png$
-^docs/build/
-^docs/html/
 ^html/
 \.pyc$
 ~$
--- a/README	Wed Apr 20 16:40:11 2016 -0700
+++ b/README	Thu May 05 22:13:02 2016 +0200
@@ -21,15 +21,15 @@
 We recommend reading the documentation first. An online version is
 available here:
 
-    http://evolution.experimentalworks.net/doc/
+    https://www.mercurial-scm.org/doc/evolution/
 
 Or see the ``doc/`` directory for a local copy.
 
 Contribute
 ==========
 
-Bugs are to be reported on the mercurial's bug tracker: http://bz.mercurial-scm.com/
-Use the the "evolution" component.
+Bugs are to be reported on the mercurial's bug tracker (component: evolution):
+https://bz.mercurial-scm.org/buglist.cgi?component=evolution&query_format=advanced&resolution=---
 
 Please use the patchbomb extension to send email to mercurial devel. Please
 make sure to use the evolve-ext flag when doing so. You can use a command like
@@ -56,6 +56,21 @@
 Changelog
 =========
 
+5.4.0 -- 
+
+- Some collaboration with the topic experimental extensions,
+  - hg evolve --all with consider all troubles in your current topic,
+  - preserve 'topic' during evolve,
+  - 'next' and 'prev' restrict themself to the current topic by default,
+- remove the dangerous 'kill' alias for 'prune' (because 'hg kill -1' without
+the leading 'hg' will give you an hardtime)
+- during 'hg evolve' skip unsupported merge instead of aborting
+- various documentation fix and update
+- hg summary now suggest 'hg evolve --continue when appropriate`
+- compatibility with Mercurial 3.8 'hgext' namespace package.
+- small improvement to the `hg split` instruction
+- add a 'metaedit' command to rewrite changeset meta data.
+
 5.3.0 -- 2016-02-11
 
 - split: add a new command to split changesets,
@@ -94,7 +109,7 @@
           in now in `--all --any`.
 - evolve: add a 'experimental.evolutioncommands' for fine grained commands
           enabling
-- next/prev: requires `--merge` to move with uncommited changes
+- next/prev: requires `--merge` to move with uncommitted changes
 - next: significantly reword error messages
 - next: add a --evolve flag to evolve aspiring children when on a head
 
--- a/contrib/nopushpublish.py	Wed Apr 20 16:40:11 2016 -0700
+++ b/contrib/nopushpublish.py	Thu May 05 22:13:02 2016 +0200
@@ -27,7 +27,7 @@
 
     ret = orig(repo, remote, outgoing, *args)
     if npublish:
-        raise util.Abort("Publishing push forbiden",
+        raise util.Abort("Publishing push forbidden",
                          hint="Use `hg phase -p <rev>` to manually publish them")
 
     return ret
--- a/debian/control	Wed Apr 20 16:40:11 2016 -0700
+++ b/debian/control	Thu May 05 22:13:02 2016 +0200
@@ -15,7 +15,7 @@
  librsvg2-bin,
  wget,
 Python-Version: >= 2.6
-Homepage: http://evolution.experimentalworks.net/
+Homepage: https://www.mercurial-scm.org/doc/evolution/
 
 Package: mercurial-evolve
 Architecture: all
--- a/docs/evolve-faq.rst	Wed Apr 20 16:40:11 2016 -0700
+++ b/docs/evolve-faq.rst	Thu May 05 22:13:02 2016 +0200
@@ -110,7 +110,7 @@
   $ hg record
   # commit the second part
   $ hg commit
-  # informs mercurial of what appened
+  # informs mercurial of what happened
   # current changeset (.) and previous one (.^) replace A (42)
   $ hg prune --new . --new .^ 42
 
--- a/docs/evolve-good-practice.rst	Wed Apr 20 16:40:11 2016 -0700
+++ b/docs/evolve-good-practice.rst	Thu May 05 22:13:02 2016 +0200
@@ -27,7 +27,7 @@
 There is no descent conflict detection and handling right now.
 Rewriting other people's changesets guarantees that you will get
 conflicts. Communicate with your fellow developers before trying to
-touch other people's work (which is a good pratice in any case).
+touch other people's work (which is a good practice in any case).
 
 Using multiple branches will help you to achieve this goal.
 
--- a/docs/from-mq.rst	Wed Apr 20 16:40:11 2016 -0700
+++ b/docs/from-mq.rst	Thu May 05 22:13:02 2016 +0200
@@ -85,7 +85,7 @@
 ..   $ hg record -m 'feature A'
 ..   # oups, I forgot some stuff
 ..   $ hg record babar.py
-..   $ hg amend -c .^ # .^ refer to "working directoy parent, here 'feature A'
+..   $ hg amend -c .^ # .^ refer to "working directory parent, here 'feature A'
 
 .. note: refresh is an alias for amend
 
--- a/docs/obs-terms.rst	Wed Apr 20 16:40:11 2016 -0700
+++ b/docs/obs-terms.rst	Thu May 05 22:13:02 2016 +0200
@@ -20,7 +20,7 @@
 - multiple *successors*: the *precursor* were splits in multiple
   changesets.
 
-.. The *precursors* and *successors* terms can be used on changeset directy:
+.. The *precursors* and *successors* terms can be used on changeset directly:
 
 .. :precursors: of a changeset `A` are changesets used as *precursors* by
 ..              obsolete marker using changeset `A` as *successors*
@@ -84,8 +84,8 @@
 |                     |                          | *obsolete* with at least    |
 |                     |                          | one non-obsolete descendant |
 |                     |                          |                             |
-|                     |                          | Thoses descendants prevent  |
-|                     |                          | properties of extincts      |
+|                     |                          | Those descendants prevent   |
+|                     |                          | properties of extinct       |
 |                     |                          | changesets to apply. But    |
 |                     |                          | they will refuse to be      |
 |                     |                          | pushed without --force.     |
@@ -169,7 +169,7 @@
 | Rewriting operation refuse to work on immutable changeset.                   |
 |                                                                              |
 | Obsolete markers that refer an immutable changeset as precursors have        |
-| no effect on the precussors but may have effect on the successors.           |
+| no effect on the precursors but may have effect on the successors.           |
 |                                                                              |
 | When a *mutable* changeset becomes *immutable* (changing its phase from draft|
 | to public) it is just *immutable* and loose any property of it's former      |
--- a/hgext/__init__.py	Wed Apr 20 16:40:11 2016 -0700
+++ b/hgext/__init__.py	Thu May 05 22:13:02 2016 +0200
@@ -1,1 +1,4 @@
-# Copyright 2011 Logilab SA <contact@logilab.fr>
+from __future__ import absolute_import
+import pkgutil
+__path__ = pkgutil.extend_path(__path__, __name__)
+
--- a/hgext/evolve.py	Wed Apr 20 16:40:11 2016 -0700
+++ b/hgext/evolve.py	Thu May 05 22:13:02 2016 +0200
@@ -9,11 +9,11 @@
 '''extends Mercurial feature related to Changeset Evolution
 
 This extension provides several commands to mutate history and deal with
-issues it may raise.
+resulting issues.
 
 It also:
 
-    - enables the "Changeset Obsolescence" feature of mercurial,
+    - enables the "Changeset Obsolescence" feature of Mercurial,
     - alters core commands and extensions that rewrite history to use
       this feature,
     - improves some aspect of the early implementation in Mercurial core
@@ -61,8 +61,12 @@
 
 import sys, os
 import random
-from StringIO import StringIO
-import struct
+try:
+    import StringIO as io
+    StringIO = io.StringIO
+except ImportError:
+    import io
+    StringIO = io.StringIO
 import re
 import collections
 import socket
@@ -231,7 +235,7 @@
             c(ui)
 
     def final_reposetup(self, ui, repo):
-        """Method to be used as a the extension reposetup
+        """Method to be used as the extension reposetup
 
         The following operations belong here:
 
@@ -324,7 +328,7 @@
         will be applied in the extension commandtable. This argument must be a
         string that will be searched using `extension.find` if not found and
         Abort error is raised. If the wrapping applies to an extension, it is
-        installed during `extsetup`
+        installed during `extsetup`.
 
         example::
 
@@ -398,7 +402,7 @@
     evolveopts = ui.configlist('experimental', 'evolution')
     if not evolveopts:
         evolveopts = ['all']
-        ui.setconfig('experimental', 'evolution', evolveopts)
+        ui.setconfig('experimental', 'evolution', evolveopts, 'evolve')
 
 @eh.uisetup
 def _configurecmdoptions(ui):
@@ -459,7 +463,7 @@
 # - Function to create markers
 # - useful alias pstatus and pdiff (should probably go in evolve)
 # - "troubles" method on changectx
-# - function to travel throught the obsolescence graph
+# - function to travel through the obsolescence graph
 # - function to find useful changeset to stabilize
 
 
@@ -468,22 +472,26 @@
 @eh.uisetup
 def _installalias(ui):
     if ui.config('alias', 'pstatus', None) is None:
-        ui.setconfig('alias', 'pstatus', 'status --rev .^')
+        ui.setconfig('alias', 'pstatus', 'status --rev .^', 'evolve')
     if ui.config('alias', 'pdiff', None) is None:
-        ui.setconfig('alias', 'pdiff', 'diff --rev .^')
+        ui.setconfig('alias', 'pdiff', 'diff --rev .^', 'evolve')
     if ui.config('alias', 'olog', None) is None:
-        ui.setconfig('alias', 'olog', "log -r 'precursors(.)' --hidden")
+        ui.setconfig('alias', 'olog', "log -r 'precursors(.)' --hidden",
+                     'evolve')
     if ui.config('alias', 'odiff', None) is None:
         ui.setconfig('alias', 'odiff',
-            "diff --hidden --rev 'limit(precursors(.),1)' --rev .")
+            "diff --hidden --rev 'limit(precursors(.),1)' --rev .",
+            'evolve')
     if ui.config('alias', 'grab', None) is None:
         if os.name == 'nt':
             ui.setconfig('alias', 'grab',
                 "! " + util.hgexecutable() + " rebase --dest . --rev $@ && "
-                 + util.hgexecutable() + " up tip")
+                 + util.hgexecutable() + " up tip",
+                         'evolve')
         else:
             ui.setconfig('alias', 'grab',
-                "! $HG rebase --dest . --rev $@ && $HG up tip")
+                "! $HG rebase --dest . --rev $@ && $HG up tip",
+                         'evolve')
 
 
 ### Troubled revset symbol
@@ -778,6 +786,10 @@
     else:
         # In 3.6.2, summary in core gained this feature, no need to display it
         pass
+    state = _evolvestateread(repo)
+    if state is not None:
+        # i18n: column positioning for "hg summary"
+        ui.write(_('evolve: (evolve --continue)\n'))
 
 @eh.extsetup
 def obssummarysetup(ui):
@@ -828,7 +840,7 @@
         wlock = repo.wlock()
         lock = repo.lock()
         tr = repo.transaction('rewrite')
-        if len(old.parents()) > 1: #XXX remove this unecessary limitation.
+        if len(old.parents()) > 1: #XXX remove this unnecessary limitation.
             raise error.Abort(_('cannot amend merge changesets'))
         base = old.p1()
         updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
@@ -1079,7 +1091,7 @@
     except error.UnknownCommand:
         # Commands may be disabled
         return
-    for alias, e in cmdtable.iteritems():
+    for alias, e in cmdtable.items():
         if e is entry:
             break
 
@@ -1455,9 +1467,14 @@
         revs = repo.revs(targetcat+'()')
         if revopt:
             revs = scmutil.revrange(repo, revopt) & revs
-        elif not anyopt and targetcat == 'unstable':
-            revs = set(_aspiringdescendant(repo,
-                                           repo.revs('(.::) - obsolete()::')))
+        elif not anyopt:
+            topic = getattr(repo, 'currenttopic', '')
+            if topic:
+                revs = repo.revs('topic(%s)', topic) & revs
+            elif targetcat == 'unstable':
+                revs = _aspiringdescendant(repo,
+                                           repo.revs('(.::) - obsolete()::'))
+                revs = set(revs)
         if targetcat == 'divergent':
             # Pick one divergent per group of divergents
             revs = _dedupedivergents(repo, revs)
@@ -1510,6 +1527,115 @@
     ordering.extend(sorted(dependencies))
     return ordering
 
+def divergentsets(repo, ctx):
+    """Compute sets of commits divergent with a given one"""
+    cache = {}
+    succsets = {}
+    base = {}
+    for n in obsolete.allprecursors(repo.obsstore, [ctx.node()]):
+        if n == ctx.node():
+            # a node can't be a base for divergence with itself
+            continue
+        nsuccsets = obsolete.successorssets(repo, n, cache)
+        for nsuccset in nsuccsets:
+            if ctx.node() in nsuccset:
+                # we are only interested in *other* successor sets
+                continue
+            if tuple(nsuccset) in base:
+                # we already know the latest base for this divergency
+                continue
+            base[tuple(nsuccset)] = n
+    divergence = []
+    for divset, b in base.iteritems():
+        divergence.append({
+            'divergentnodes': divset,
+            'commonprecursor': b
+        })
+
+    return divergence
+
+def _preparelistctxs(items, condition):
+    return [item.hex() for item in items if condition(item)]
+
+def _formatctx(fm, ctx):
+    fm.data(node=ctx.hex())
+    fm.data(desc=ctx.description())
+    fm.data(date=ctx.date())
+    fm.data(user=ctx.user())
+
+def listtroubles(ui, repo, troublecategories, **opts):
+    """Print all the troubles for the repo (or given revset)"""
+    troublecategories = troublecategories or ['divergent', 'unstable', 'bumped']
+    showunstable = 'unstable' in troublecategories
+    showbumped = 'bumped' in troublecategories
+    showdivergent = 'divergent' in troublecategories
+
+    revs = repo.revs('+'.join("%s()" % t for t in troublecategories))
+    if opts.get('rev'):
+        revs = revs & repo.revs(opts.get('rev'))
+
+    fm = ui.formatter('evolvelist', opts)
+    for rev in revs:
+        ctx = repo[rev]
+        unpars = _preparelistctxs(ctx.parents(), lambda p: p.unstable())
+        obspars = _preparelistctxs(ctx.parents(), lambda p: p.obsolete())
+        imprecs = _preparelistctxs(repo.set("allprecursors(%n)", ctx.node()),
+                                   lambda p: not p.mutable())
+        dsets = divergentsets(repo, ctx)
+
+        fm.startitem()
+        # plain formatter section
+        hashlen, desclen = 12, 60
+        desc = ctx.description()
+        if desc:
+            desc = desc.splitlines()[0]
+        desc = (desc[:desclen] + '...') if len(desc) > desclen else desc
+        fm.plain('%s: ' % ctx.hex()[:hashlen])
+        fm.plain('%s\n' % desc)
+        fm.data(node=ctx.hex(), rev=ctx.rev(), desc=desc, phase=ctx.phasestr())
+
+        for unpar in unpars if showunstable else []:
+            fm.plain('  unstable: %s (unstable parent)\n' % unpar[:hashlen])
+        for obspar in obspars if showunstable else []:
+            fm.plain('  unstable: %s (obsolete parent)\n' % obspar[:hashlen])
+        for imprec in imprecs if showbumped else []:
+            fm.plain('  bumped: %s (immutable precursor)\n' % imprec[:hashlen])
+
+        if dsets and showdivergent:
+            for dset in dsets:
+                fm.plain('  divergent: ')
+                first = True
+                for n in dset['divergentnodes']:
+                    t = "%s (%s)" if first else " %s (%s)"
+                    first = False
+                    fm.plain(t % (node.hex(n)[:hashlen], repo[n].phasestr()))
+                comprec = node.hex(dset['commonprecursor'])[:hashlen]
+                fm.plain(" (precursor %s)\n" % comprec)
+        fm.plain("\n")
+
+        # templater-friendly section
+        _formatctx(fm, ctx)
+        troubles = []
+        for unpar in unpars:
+            troubles.append({'troubletype': 'unstable', 'sourcenode': unpar,
+                             'sourcetype': 'unstableparent'})
+        for obspar in obspars:
+            troubles.append({'troubletype': 'unstable', 'sourcenode': obspar,
+                             'sourcetype': 'obsoleteparent'})
+        for imprec in imprecs:
+            troubles.append({'troubletype': 'bumped', 'sourcenode': imprec,
+                             'sourcetype': 'immutableprecursor'})
+        for dset in dsets:
+            divnodes = [{'node': node.hex(n),
+                         'phase': repo[n].phasestr(),
+                        } for n in dset['divergentnodes']]
+            troubles.append({'troubletype': 'divergent',
+                             'commonprecursor': node.hex(dset['commonprecursor']),
+                             'divergentnodes': divnodes})
+        fm.data(troubles=troubles)
+
+    fm.end()
+
 @command('^evolve|stabilize|solve',
     [('n', 'dry-run', False,
         _('do not perform actions, just print what would be done')),
@@ -1525,6 +1651,7 @@
     ('a', 'all', False, _('evolve all troubled changesets related to the '
                           'current  working directory and its descendants')),
     ('c', 'continue', False, _('continue an interrupted evolution')),
+    ('l', 'list', False, 'provide details on troubled changesets in the repo'),
     ] + mergetoolopts,
     _('[OPTIONS]...'))
 def evolve(ui, repo, **opts):
@@ -1592,9 +1719,13 @@
     (the default). You can combine ``--bumped`` or ``--divergent`` with
     ``--rev``, ``--all``, or ``--any``.
 
+    You can also use the evolve command to list the troubles affecting your
+    repository by using the --list flag. You can choose to display only some
+    categories of troubles with the --unstable, --divergent or --bumped flags.
     """
 
     # Options
+    listopt = opts['list']
     contopt = opts['continue']
     anyopt = opts['any']
     allopt = opts['all']
@@ -1604,6 +1735,10 @@
     revopt = opts['rev']
     troublecategories = ['bumped', 'divergent', 'unstable']
     specifiedcategories = [t for t in troublecategories if opts[t]]
+    if listopt:
+        listtroubles(ui, repo, specifiedcategories, **opts)
+        return
+
     targetcat = 'unstable'
     if 1 < len(specifiedcategories):
         msg = _('cannot specify more than one trouble category to solve (yet)')
@@ -1645,7 +1780,7 @@
 
     def progresscb():
         if revopt or allopt:
-            ui.progress(_('evolve'), seen, unit='changesets', total=count)
+            ui.progress(_('evolve'), seen, unit=_('changesets'), total=count)
 
     # Continuation handling
     if contopt:
@@ -1753,10 +1888,12 @@
         if not pctx.obsolete():
             pctx = orig.p2()  # second parent is obsolete ?
         elif orig.p2().obsolete():
-            raise error.Abort(_("no support for evolving merge changesets "
-                                "with two obsolete parents yet"),
-                              hint=_("Redo the merge and use `hg prune <old> "
-                                   "--succ <new>` to obsolete the old one"))
+            hint = _("Redo the merge (%s) and use `hg prune <old> "
+                     "--succ <new>` to obsolete the old one") % orig.hex()[:12]
+            ui.warn(_("warning: no support for evolving merge changesets "
+                      "with two obsolete parents yet\n") +
+                    _("(%s)\n") % hint)
+            return False
 
     if not pctx.obsolete():
         ui.warn(_("cannot solve instability of %s, skipping\n") % orig)
@@ -2027,14 +2164,14 @@
 /!\ * hg up to the parent of the amended changeset (which are named W and Z)
 /!\ * hg revert --all -r X
 /!\ * hg ci -m "same message as the amended changeset" => new cset Y
-/!\ * hg kill -n Y W Z
+/!\ * hg prune -n Y W Z
 """)
     if progresscb: progresscb()
     emtpycommitallowed = repo.ui.backupconfig('ui', 'allowemptycommit')
     tr = repo.currenttransaction()
     assert tr is not None
     try:
-        repo.ui.setconfig('ui', 'allowemptycommit', True)
+        repo.ui.setconfig('ui', 'allowemptycommit', True, 'evolve')
         repo.dirstate.beginparentchange()
         repo.dirstate.setparents(divergent.node(), node.nullid)
         repo.dirstate.endparentchange()
@@ -2075,6 +2212,7 @@
          [('B', 'move-bookmark', False,
              _('move active bookmark after update')),
           ('', 'merge', False, _('bring uncommitted change along')),
+          ('', 'no-topic', False, _('ignore topic and move topologically')),
           ('n', 'dry-run', False,
              _('do not perform actions, just print what would be done'))],
          '[OPTION]...')
@@ -2095,8 +2233,14 @@
             raise
 
     parents = wparents[0].parents()
+    topic = getattr(repo, 'currenttopic', '')
+    if topic and not opts.get("no_topic", False):
+        parents = [ctx for ctx in parents if ctx.topic() == topic]
     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
-    if len(parents) == 1:
+    if not parents:
+        ui.warn(_('no parent in topic "%s"\n') % topic)
+        ui.warn(_('(do you want --no-topic)\n'))
+    elif len(parents) == 1:
         p = parents[0]
         bm = bmactive(repo)
         shouldmove = opts.get('move_bookmark') and bm is not None
@@ -2133,6 +2277,7 @@
              _('move active bookmark after update')),
           ('', 'merge', False, _('bring uncommitted change along')),
           ('', 'evolve', False, _('evolve the next changeset if necessary')),
+          ('', 'no-topic', False, _('ignore topic and move topologically')),
           ('n', 'dry-run', False,
               _('do not perform actions, just print what would be done'))],
               '[OPTION]...')
@@ -2156,6 +2301,12 @@
             raise
 
     children = [ctx for ctx in wparents[0].children() if not ctx.obsolete()]
+    topic = getattr(repo, 'currenttopic', '')
+    filtered = []
+    if topic and not opts.get("no_topic", False):
+        filtered = [ctx for ctx in children if ctx.topic() != topic]
+        # XXX N-square membership on children
+        children = [ctx for ctx in children if ctx not in filtered]
     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
     if len(children) == 1:
         c = children[0]
@@ -2191,8 +2342,17 @@
         result = 1
     else:
         aspchildren = _aspiringchildren(repo, [repo['.'].rev()])
+        if topic:
+            filtered.extend(repo[c] for c in children
+                            if repo[c].topic() != topic)
+            # XXX N-square membership on children
+            aspchildren = [ctx for ctx in aspchildren if ctx not in filtered]
         if not opts['evolve'] or not aspchildren:
-            ui.warn(_('no children\n'))
+            if filtered:
+                ui.warn(_('no children on topic "%s"\n') % topic)
+                ui.warn(_('do you want --no-topic\n'))
+            else:
+                ui.warn(_('no children\n'))
             if aspchildren:
                 msg = _('(%i unstable changesets to be evolved here, '
                         'do you want --evolve?)\n')
@@ -2272,7 +2432,7 @@
     return metadata
 
 
-@command('^prune|obsolete|kill',
+@command('^prune|obsolete',
     [('n', 'new', [], _("successor changeset (DEPRECATED)")),
      ('s', 'succ', [], _("successor changeset")),
      ('r', 'rev', [], _("revisions to prune")),
@@ -2349,9 +2509,8 @@
         if not precs:
             raise error.Abort('nothing to prune')
 
-        if not obsolete.isenabled(repo, obsolete.allowunstableopt):
-            if repo.revs("(%ld::) - %ld", revs, revs):
-                raise error.Abort(_("cannot prune in the middle of a stack"))
+        if _disallowednewunstable(repo, revs):
+            raise error.Abort(_("cannot prune in the middle of a stack"))
 
         # defines successors changesets
         sucs = scmutil.revrange(repo, succs)
@@ -2359,7 +2518,9 @@
         sucs = tuple(repo[n] for n in sucs)
         if not biject and len(sucs) > 1 and len(precs) > 1:
             msg = "Can't use multiple successors for multiple precursors"
-            raise error.Abort(msg)
+            hint = _("use --biject to mark a series as a replacement"
+                     " for another")
+            raise error.Abort(msg, hint=hint)
         elif biject and len(sucs) != len(precs):
             msg = "Can't use %d successors for %d precursors" \
                 % (len(sucs), len(precs))
@@ -2685,7 +2846,7 @@
         if obsoleted:
             obsoleted = repo.set('%lr', obsoleted)
         result = orig(ui, repo, *arg, **kwargs)
-        if not result: # commit successed
+        if not result: # commit succeeded
             new = repo['-1']
             oldbookmarks = []
             markers = []
@@ -2758,7 +2919,8 @@
         def haschanges():
             modified, added, removed, deleted = repo.status()[:4]
             return modified or added or removed or deleted
-        msg = 'HG: Please, edit the original changeset description.\n\n'
+        msg = ("HG: This is the original pre-split commit message. "
+               "Edit it as appropriate.\n\n")
         msg += ctx.description()
         opts['message'] = msg
         opts['edit'] = True
@@ -2961,27 +3123,13 @@
         ui.write_err(_('single revision specified, nothing to fold\n'))
         return 1
 
-    roots = repo.revs('roots(%ld)', revs)
-    if len(roots) > 1:
-        raise error.Abort(_("cannot fold non-linear revisions "
-                           "(multiple roots given)"))
-    root = repo[roots.first()]
-    if root.phase() <= phases.public:
-        raise error.Abort(_("cannot fold public revisions"))
-    heads = repo.revs('heads(%ld)', revs)
-    if len(heads) > 1:
-        raise error.Abort(_("cannot fold non-linear revisions "
-                           "(multiple heads given)"))
-    head = repo[heads.first()]
-    disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
-    if disallowunstable:
-        if repo.revs("(%ld::) - %ld", revs, revs):
-            raise error.Abort(_("cannot fold chain not ending with a head "\
-                               "or with branching"))
     wlock = lock = None
     try:
         wlock = repo.wlock()
         lock = repo.lock()
+
+        root, head = _foldcheck(repo, revs)
+
         tr = repo.transaction('touch')
         try:
             commitopts = opts.copy()
@@ -3013,7 +3161,147 @@
     finally:
         lockmod.release(lock, wlock)
 
-
+@command('^metaedit',
+         [('r', 'rev', [], _("revision to edit")),
+         ('', 'fold', None, _("also fold specified revisions into one")),
+         ] + commitopts + commitopts2,
+         _('hg metaedit [OPTION]... [-r] [REV]'))
+def metaedit(ui, repo, *revs, **opts):
+    """edit commit information
+
+    Edits the commit information for the specified revisions. By default, edits
+    commit information for the working directory parent.
+
+    With --fold, also folds multiple revisions into one if necessary. In this
+    case, the given revisions must form a linear unbroken chain.
+
+    .. container:: verbose
+
+     Some examples:
+
+     - Edit the commit message for the working directory parent::
+
+         hg metaedit
+
+     - Change the username for the working directory parent::
+
+         hg metaedit --user 'New User <new-email@example.com>'
+
+     - Combine all draft revisions that are ancestors of foo but not of @ into
+       one::
+
+         hg metaedit --fold 'draft() and only(foo,@)'
+
+       See :hg:`help phases` for more about draft revisions, and
+       :hg:`help revsets` for more about the `draft()` and `only()` keywords.
+    """
+    revs = list(revs)
+    revs.extend(opts['rev'])
+    if not revs:
+        if opts['fold']:
+            raise error.Abort(_('revisions must be specified with --fold'))
+        revs = ['.']
+
+    wlock = lock = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+
+        revs = scmutil.revrange(repo, revs)
+        if not opts['fold'] and len(revs) > 1:
+            # TODO: handle multiple revisions. This is somewhat tricky because
+            # if we want to edit a series of commits:
+            #
+            #   a ---- b ---- c
+            #
+            # we need to rewrite a first, then directly rewrite b on top of the
+            # new a, then rewrite c on top of the new b. So we need to handle
+            # revisions in topological order.
+            raise error.Abort(_('editing multiple revisions without --fold is '
+                                'not currently supported'))
+
+        if opts['fold']:
+            root, head = _foldcheck(repo, revs)
+        else:
+            if repo.revs("%ld and public()", revs):
+                raise error.Abort(_('cannot edit commit information for public '
+                                    'revisions'))
+            newunstable = _disallowednewunstable(repo, revs)
+            if newunstable:
+                raise error.Abort(
+                    _('cannot edit commit information in the middle of a stack'),
+                    hint=_('%s will be affected') % repo[newunstable.first()])
+            root = head = repo[revs.first()]
+
+        wctx = repo[None]
+        p1 = wctx.p1()
+        tr = repo.transaction('metaedit')
+        newp1 = None
+        try:
+            commitopts = opts.copy()
+            allctx = [repo[r] for r in revs]
+            targetphase = max(c.phase() for c in allctx)
+
+            if commitopts.get('message') or commitopts.get('logfile'):
+                commitopts['edit'] = False
+            else:
+                if opts['fold']:
+                    msgs = ["HG: This is a fold of %d changesets." % len(allctx)]
+                    msgs += ["HG: Commit message of changeset %s.\n\n%s\n" %
+                             (c.rev(), c.description()) for c in allctx]
+                else:
+                    msgs = [head.description()]
+                commitopts['message'] =  "\n".join(msgs)
+                commitopts['edit'] = True
+
+            # TODO: if the author and message are the same, don't create a new
+            # hash. Right now we create a new hash because the date can be
+            # different.
+            newid, created = rewrite(repo, root, allctx, head,
+                                     [root.p1().node(), root.p2().node()],
+                                     commitopts=commitopts)
+            if created:
+                if p1.rev() in revs:
+                    newp1 = newid
+                phases.retractboundary(repo, tr, targetphase, [newid])
+                obsolete.createmarkers(repo, [(ctx, (repo[newid],))
+                                              for ctx in allctx])
+            else:
+                ui.status(_("nothing changed\n"))
+            tr.close()
+        finally:
+            tr.release()
+
+        if opts['fold']:
+            ui.status('%i changesets folded\n' % len(revs))
+        if newp1 is not None:
+            hg.update(repo, newp1)
+    finally:
+        lockmod.release(lock, wlock)
+
+def _foldcheck(repo, revs):
+    roots = repo.revs('roots(%ld)', revs)
+    if len(roots) > 1:
+        raise error.Abort(_("cannot fold non-linear revisions "
+                           "(multiple roots given)"))
+    root = repo[roots.first()]
+    if root.phase() <= phases.public:
+        raise error.Abort(_("cannot fold public revisions"))
+    heads = repo.revs('heads(%ld)', revs)
+    if len(heads) > 1:
+        raise error.Abort(_("cannot fold non-linear revisions "
+                           "(multiple heads given)"))
+    head = repo[heads.first()]
+    if _disallowednewunstable(repo, revs):
+        raise error.Abort(_("cannot fold chain not ending with a head "\
+                            "or with branching"))
+    return root, head
+
+def _disallowednewunstable(repo, revs):
+    allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
+    if allowunstable:
+        return revset.baseset()
+    return repo.revs("(%ld::) - %ld", revs, revs)
 
 @eh.wrapcommand('graft')
 def graftwrapper(orig, ui, repo, *revs, **kwargs):
@@ -3044,7 +3332,7 @@
 
 @eh.extsetup
 def oldevolveextsetup(ui):
-    for cmd in ['kill', 'uncommit', 'touch', 'fold']:
+    for cmd in ['prune', 'uncommit', 'touch', 'fold']:
         try:
             entry = extensions.wrapcommand(cmdtable, cmd,
                                            warnobserrors)
@@ -3246,7 +3534,7 @@
         undecided.difference_update(common)
 
 
-    ui.progress(_("comparing with other"), None, total=totalnb)
+    ui.progress(_("comparing with other"), None)
     result = dag.headsetofconnecteds(common)
     ui.debug("%d total queries\n" % roundtrips)
 
@@ -3265,7 +3553,7 @@
         return len(self.getvalue())
 
     def read(self, size=None):
-        obsexcprg(self.ui, self.tell(), unit="bytes", total=self.length)
+        obsexcprg(self.ui, self.tell(), unit=_("bytes"), total=self.length)
         return StringIO.read(self, size)
 
     def __iter__(self):
@@ -3317,11 +3605,11 @@
                                % (len(markers), len(remotedata), totalbytes),
                       True)
             for key, data in remotedata:
-                obsexcprg(repo.ui, sentbytes, item=key, unit="bytes",
+                obsexcprg(repo.ui, sentbytes, item=key, unit=_("bytes"),
                           total=totalbytes)
                 rslts.append(remote.pushkey('obsolete', key, '', data))
                 sentbytes += len(data)
-                obsexcprg(repo.ui, sentbytes, item=key, unit="bytes",
+                obsexcprg(repo.ui, sentbytes, item=key, unit=_("bytes"),
                           total=totalbytes)
             obsexcprg(repo.ui, None)
             if [r for r in rslts if not r]:
@@ -3530,12 +3818,12 @@
     current = 0
     data = StringIO()
     ui = self.ui
-    obsexcprg(ui, current, unit="bytes", total=length)
+    obsexcprg(ui, current, unit=_("bytes"), total=length)
     while current < length:
         readsize = min(length - current, chunk)
         data.write(f.read(readsize))
         current += readsize
-        obsexcprg(ui, current, unit="bytes", total=length)
+        obsexcprg(ui, current, unit=_("bytes"), total=length)
     obsexcprg(ui, None)
     data.seek(0)
     return data
@@ -3718,7 +4006,7 @@
     backup = repo.ui.backupconfig('phases', 'new-commit')
     try:
         targetphase = max(orig.phase(), phases.draft)
-        repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
+        repo.ui.setconfig('phases', 'new-commit', targetphase, 'evolve')
         # Commit might fail if unresolved files exist
         nodenew = repo.commit(text=commitmsg, user=orig.user(),
                               date=orig.date(), extra=extra)
@@ -3780,7 +4068,7 @@
 def _evolvestateread(repo):
     try:
         f = repo.vfs('evolvestate')
-    except IOError, err:
+    except IOError as err:
         if err.errno != errno.ENOENT:
             raise
         return None
@@ -3834,6 +4122,14 @@
     bmdeactivate(repo)
     if keepbranch:
        repo.dirstate.setbranch(orig.branch())
+    if util.safehasattr(repo, 'currenttopic'):
+        # uurrgs
+        # there no other topic setter yet
+        if not orig.topic() and repo.vfs.exists('topic'):
+                repo.vfs.unlink('topic')
+        else:
+            with repo.vfs.open('topic', 'w') as f:
+                f.write(orig.topic())
 
     try:
        r = merge.graft(repo, orig, pctx, ['local', 'graft'], True)
--- a/hgext/obsolete.py	Wed Apr 20 16:40:11 2016 -0700
+++ b/hgext/obsolete.py	Thu May 05 22:13:02 2016 +0200
@@ -3,12 +3,12 @@
 #
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
-"""Deprecated extension that formely introduces "Changeset Obsolescence".
+"""Deprecated extension that formerly introduced "Changeset Obsolescence".
 
-This concept is now partially in Mercurial core (starting with mercurial 2.3).
-The remaining logic have been grouped with the evolve extension.
+This concept is now partially in Mercurial core (starting with Mercurial 2.3).
+The remaining logic has been grouped with the evolve extension.
 
-Some code cemains in this extensions to detect and convert prehistoric format
+Some code remains in this extensions to detect and convert prehistoric format
 of obsolete marker than early user may have create. Keep it enabled if you
 were such user.
 """
@@ -57,10 +57,10 @@
             raise error.Abort('old format of obsolete marker detected!\n'
                               'run `hg debugconvertobsolete` once.')
 
-def _obsdeserialise(flike):
-    """read a file like object serialised with _obsserialise
+def _obsdeserialize(flike):
+    """read a file like object serialized with _obsserialize
 
-    this desierialize into a {subject -> objects} mapping
+    this deserialize into a {subject -> objects} mapping
 
     this was the very first format ever."""
     rels = {}
--- a/setup.py	Wed Apr 20 16:40:11 2016 -0700
+++ b/setup.py	Thu May 05 22:13:02 2016 +0200
@@ -29,7 +29,7 @@
     author='Pierre-Yves David',
     maintainer='Pierre-Yves David',
     maintainer_email='pierre-yves.david@ens-lyon.org',
-    url='http://evolution.experimentalworks.net/',
+    url='https://www.mercurial-scm.org/doc/evolution/',
     description='Flexible evolution of Mercurial history.',
     long_description=open('README').read(),
     keywords='hg mercurial',
--- a/tests/test-amend.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-amend.t	Thu May 05 22:13:02 2016 +0200
@@ -107,7 +107,7 @@
   $ HGUSER=
   $ hg amend -e --config ui.username= -m "empty user"
   abort: no username supplied
-  (use "hg config --edit" to set your username)
+  (use 'hg config --edit' to set your username)
   [255]
   $ hg sum
   parent: 8:* tip (glob)
--- a/tests/test-corrupt.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-corrupt.t	Thu May 05 22:13:02 2016 +0200
@@ -101,7 +101,7 @@
      summary:     add A
   
 
-  $ hg kill --fold -n -1 -- -2 -3
+  $ hg prune --fold -n -1 -- -2 -3
   2 changesets pruned
   $ hg push ../other
   pushing to ../other
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-list.t	Thu May 05 22:13:02 2016 +0200
@@ -0,0 +1,80 @@
+Set up some configs
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > rebase=
+  > EOF
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+Test the instability listing
+  $ hg init r2
+  $ cd r2
+  $ echo a > a && hg ci -Am a
+  adding a
+  $ echo b > b && hg ci -Am b
+  adding b
+  $ echo c > c && hg ci -Am c
+  adding c
+  $ hg up 0
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ echo a >> a && hg ci --amend -m a
+  2 new unstable changesets
+  $ hg evolve --list
+  d2ae7f538514: b
+    unstable: cb9a9f314b8b (obsolete parent)
+  
+  177f92b77385: c
+    unstable: d2ae7f538514 (unstable parent)
+  
+  $ cd ..
+
+Test the bumpedness listing
+  $ hg init r3
+  $ cd r3
+  $ echo a > a && hg ci -Am a
+  adding a
+  $ echo b > b && hg ci --amend -m ab
+  $ hg phase --public --rev 0 --hidden
+  1 new bumped changesets
+  $ hg evolve --list
+  88cc282e27fc: ab
+    bumped: cb9a9f314b8b (immutable precursor)
+  
+  $ cd ..
+
+Test the divergence listing
+  $ hg init r1
+  $ cd r1
+  $ echo a > a && hg ci -Am a
+  adding a
+  $ hg up 0
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo b > b && hg ci -Am b
+  adding b
+  $ hg up 0
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo c > c && hg ci -Am c
+  adding c
+  created new head
+  $ hg up 0
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo d > d && hg ci -Am d
+  adding d
+  created new head
+  $ hg rebase -s 1 -d 2
+  rebasing 1:d2ae7f538514 "b"
+  $ hg rebase -s 1 -d 3 --hidden --config experimental.allowdivergence=True
+  rebasing 1:d2ae7f538514 "b"
+  2 new divergent changesets
+  $ hg evolve --list
+  c882616e9d84: b
+    divergent: a922b3733e98 (draft) (precursor d2ae7f538514)
+  
+  a922b3733e98: b
+    divergent: c882616e9d84 (draft) (precursor d2ae7f538514)
+  
+  $ hg phase -p a922b3733e98
+  $ hg evolve --list
+  c882616e9d84: b
+    divergent: a922b3733e98 (public) (precursor d2ae7f538514)
+  
+  $ cd ..
--- a/tests/test-evolve-order.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-evolve-order.t	Thu May 05 22:13:02 2016 +0200
@@ -155,6 +155,7 @@
   |/
   o  15:739f18ac1d03@default(draft) add _d
   |
+  ~
 
 Second set of stack with no successor for b2_:
   $ mkstack "desc(_d)" b1_ b2_ b3_ b4_ >/dev/null
@@ -196,6 +197,7 @@
   |/
   o  15:739f18ac1d03@default(draft) add _d
   |
+  ~
 
 Solve the full second stack and only part of the first one
   $ echo "(desc(_d)::) - desc(c3_)"
@@ -232,6 +234,7 @@
   |/
   o  15:739f18ac1d03@default(draft) add _d
   |
+  ~
 
 Test multiple revision with some un-evolvable because parent is splitted
 ------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-evolve-topic.t	Thu May 05 22:13:02 2016 +0200
@@ -0,0 +1,219 @@
+
+Check we can find the topic extensions
+
+  $ [ -z "$HGTEST_TOPICROOT" ] && echo 'skipped: $HGTEST_TOPICROOT not set' >&2 && exit 80
+  [1]
+  $ [ ! -e $HGTEST_TOPICROOT/hgext3rd/topic/__init__.py ] && echo 'skipped: no topic repo found at $HGTEST_TOPICROOT' >&2 && exit 80
+  [1]
+  $ cat >> $HGRCPATH <<EOF
+  > [defaults]
+  > amend=-d "0 0"
+  > fold=-d "0 0"
+  > [phases]
+  > publish = False
+  > [ui]
+  > logtemplate = {rev} - \{{get(namespaces, "topics")}} {node|short} {desc} ({phase})\n
+  > [diff]
+  > git = 1
+  > unified = 0
+  > [extensions]
+  > rebase = 
+  > topic = $HGTEST_TOPICROOT/hgext3rd/topic/
+  > EOF
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "add $1"
+  > }
+
+Create a simple setup
+
+  $ hg init repoa
+  $ cd repoa
+  $ mkcommit aaa
+  $ mkcommit bbb
+  $ hg topic foo
+  $ mkcommit ccc
+  $ mkcommit ddd
+  $ mkcommit eee
+  $ mkcommit fff
+  $ hg topic bar
+  $ mkcommit ggg
+  $ mkcommit hhh
+  $ mkcommit iii
+  $ mkcommit jjj
+
+  $ hg log -G
+  @  9 - {bar} 1d964213b023 add jjj (draft)
+  |
+  o  8 - {bar} fcab990f3261 add iii (draft)
+  |
+  o  7 - {bar} b0c2554835ac add hhh (draft)
+  |
+  o  6 - {bar} c748293f1c1a add ggg (draft)
+  |
+  o  5 - {foo} 6a6b7365c751 add fff (draft)
+  |
+  o  4 - {foo} 3969ab847d9c add eee (draft)
+  |
+  o  3 - {foo} 4e3a154f38c7 add ddd (draft)
+  |
+  o  2 - {foo} cced9bac76e3 add ccc (draft)
+  |
+  o  1 - {} a4dbed0837ea add bbb (draft)
+  |
+  o  0 - {} 199cc73e9a0b add aaa (draft)
+  
+
+Test that evolve --all evolve the current topic
+-----------------------------------------------
+
+make a mess
+
+  $ hg up foo
+  switching to topic foo
+  0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+  $ hg topic -l 
+  t4@ add fff (current)
+  t3: add eee
+  t2: add ddd
+  t1: add ccc
+    ^ add bbb
+  $ hg up 'desc(ddd)'
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ echo ddd >> ddd
+  $ hg amend
+  6 new unstable changesets
+  $ hg up 'desc(fff)'
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo fff >> fff
+  $ hg amend
+
+  $ hg log -G
+  @  13 - {foo} e104f49bab28 add fff (draft)
+  |
+  | o  11 - {foo} d9cacd156ffc add ddd (draft)
+  | |
+  | | o  9 - {bar} 1d964213b023 add jjj (draft)
+  | | |
+  | | o  8 - {bar} fcab990f3261 add iii (draft)
+  | | |
+  | | o  7 - {bar} b0c2554835ac add hhh (draft)
+  | | |
+  | | o  6 - {bar} c748293f1c1a add ggg (draft)
+  | | |
+  +---x  5 - {foo} 6a6b7365c751 add fff (draft)
+  | |
+  o |  4 - {foo} 3969ab847d9c add eee (draft)
+  | |
+  x |  3 - {foo} 4e3a154f38c7 add ddd (draft)
+  |/
+  o  2 - {foo} cced9bac76e3 add ccc (draft)
+  |
+  o  1 - {} a4dbed0837ea add bbb (draft)
+  |
+  o  0 - {} 199cc73e9a0b add aaa (draft)
+  
+
+Run evolve --all
+
+  $ hg evolve --all
+  move:[4] add eee
+  atop:[11] add ddd
+  move:[13] add fff
+  atop:[14] add eee
+  working directory is now at 070c5573d8f9
+  $ hg log -G
+  @  15 - {foo} 070c5573d8f9 add fff (draft)
+  |
+  o  14 - {foo} 42b49017ff90 add eee (draft)
+  |
+  o  11 - {foo} d9cacd156ffc add ddd (draft)
+  |
+  | o  9 - {bar} 1d964213b023 add jjj (draft)
+  | |
+  | o  8 - {bar} fcab990f3261 add iii (draft)
+  | |
+  | o  7 - {bar} b0c2554835ac add hhh (draft)
+  | |
+  | o  6 - {bar} c748293f1c1a add ggg (draft)
+  | |
+  | x  5 - {foo} 6a6b7365c751 add fff (draft)
+  | |
+  | x  4 - {foo} 3969ab847d9c add eee (draft)
+  | |
+  | x  3 - {foo} 4e3a154f38c7 add ddd (draft)
+  |/
+  o  2 - {foo} cced9bac76e3 add ccc (draft)
+  |
+  o  1 - {} a4dbed0837ea add bbb (draft)
+  |
+  o  0 - {} 199cc73e9a0b add aaa (draft)
+  
+
+Test that evolve does not loose topic information
+-------------------------------------------------
+
+  $ hg evolve --rev 'topic(bar)'
+  move:[6] add ggg
+  atop:[15] add fff
+  move:[7] add hhh
+  atop:[16] add ggg
+  move:[8] add iii
+  atop:[17] add hhh
+  move:[9] add jjj
+  atop:[18] add iii
+  working directory is now at 9bf430c106b7
+  $ hg log -G
+  @  19 - {bar} 9bf430c106b7 add jjj (draft)
+  |
+  o  18 - {bar} d2dc89c57700 add iii (draft)
+  |
+  o  17 - {bar} 20bc4d02aa62 add hhh (draft)
+  |
+  o  16 - {bar} 16d6f664b17c add ggg (draft)
+  |
+  o  15 - {foo} 070c5573d8f9 add fff (draft)
+  |
+  o  14 - {foo} 42b49017ff90 add eee (draft)
+  |
+  o  11 - {foo} d9cacd156ffc add ddd (draft)
+  |
+  o  2 - {foo} cced9bac76e3 add ccc (draft)
+  |
+  o  1 - {} a4dbed0837ea add bbb (draft)
+  |
+  o  0 - {} 199cc73e9a0b add aaa (draft)
+  
+
+Tests next and prev behavior
+============================
+
+Basic move are restricted to the current topic
+
+  $ hg up foo
+  switching to topic foo
+  0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+  $ hg prev
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  [14] add eee
+  $ hg next
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  [15] add fff
+  $ hg next
+  no children on topic "foo"
+  do you want --no-topic
+  [1]
+  $ hg next --no-topic
+  switching to topic bar
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  [16] add ggg
+  $ hg prev
+  no parent in topic "bar"
+  (do you want --no-topic)
+  $ hg prev --no-topic
+  switching to topic foo
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  [15] add fff
--- a/tests/test-evolve.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-evolve.t	Thu May 05 22:13:02 2016 +0200
@@ -2,6 +2,7 @@
   > [defaults]
   > amend=-d "0 0"
   > fold=-d "0 0"
+  > metaedit=-d "0 0"
   > [web]
   > push_ssl = false
   > allow_push = *
@@ -112,7 +113,7 @@
 
   $ hg log -r 1 --template '{rev} {phase} {obsolete}\n'
   1 public stable
-  $ hg kill 1
+  $ hg prune 1
   abort: cannot prune immutable changeset: 7c3bad9141dc
   (see "hg help phases" for details)
   [255]
@@ -123,7 +124,7 @@
 
   $ hg id -n
   5
-  $ hg kill .
+  $ hg prune .
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at fbb94e3a0ecf
   1 changesets pruned
@@ -136,7 +137,7 @@
 
 test multiple kill
 
-  $ hg kill 4 -r 3
+  $ hg prune 4 -r 3
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at 7c3bad9141dc
   2 changesets pruned
@@ -151,7 +152,7 @@
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ echo 4 > g
   $ hg add g
-  $ hg kill .
+  $ hg prune .
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at 7c3bad9141dc
   1 changesets pruned
@@ -594,7 +595,7 @@
   merging 1
   warning: conflicts while merging 1! (edit, then use 'hg resolve --mark')
   abort: unresolved conflicts, can't continue
-  (use hg resolve and hg graft --continue)
+  (use 'hg resolve' and 'hg graft --continue')
   [255]
   $ hg log -r7 --template '{rev}:{node|short} {obsolete}\n'
   7:a5bfd90a2f29 stable
@@ -790,7 +791,7 @@
   adding b
   $ hg mv a c
   $ hg ci -m c
-  $ hg kill .^
+  $ hg prune .^
   1 changesets pruned
   1 new unstable changesets
   $ hg stab --any
@@ -1224,6 +1225,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
 
   $ hg evolve --rev 23 --any
   abort: cannot specify both "--rev" and "--any"
@@ -1262,6 +1264,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
 
 Check that prune respects the allowunstable option
   $ hg up -C .
@@ -1291,6 +1294,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
   $ hg up 19
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ mkcommit c5_
@@ -1312,6 +1316,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
 
 Check that fold respects the allowunstable option
   $ hg up edc3c9de504e
@@ -1329,6 +1334,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
 
   $ hg fold --exact "19 + 18"
   abort: cannot fold chain not ending with a head or with branching
@@ -1356,6 +1362,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
 
 Create a split commit
   $ printf "oo" > oo;
@@ -1392,6 +1399,7 @@
   |/
   o  18:edc3c9de504e@default(draft) a3
   |
+  ~
   $ hg evolve --rev "18::"
   move:[33] add uu
   atop:[35] _pp
@@ -1446,6 +1454,124 @@
   |/
   o  36:43c3f5ef149f@default(draft) add uu
   |
+  ~
 
   $ 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 be affected)
+  [255]
+  $ hg metaedit '18::20' --fold --config 'experimental.evolution=createmarkers, allnewcommands'
+  abort: cannot fold chain not ending with a head or with branching
+  [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-inhibit.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-inhibit.t	Thu May 05 22:13:02 2016 +0200
@@ -419,7 +419,7 @@
   abort: hidden revision '3'!
   (use --hidden to access hidden revisions)
   [255]
-  $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d  2db36d8066ff
+  $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d  2db36d8066ff --config experimental.rebaseskipobsolete=0
   Warning: accessing hidden changesets 2db36d8066ff for write operation
   Warning: accessing hidden changesets ad78ff7d621f,53a94305e133 for write operation
   rebasing 10:ad78ff7d621f "add cK"
@@ -536,6 +536,7 @@
   |/
   o  14:d66ccb8c5871 add cL
   |
+  ~
   $ hg strip -r 210589181b14
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at d66ccb8c5871
@@ -557,6 +558,7 @@
   |/
   o  14:d66ccb8c5871 add cL
   |
+  ~
 
 Test prunestrip
 
@@ -572,6 +574,7 @@
   |
   @  14:d66ccb8c5871 add cL foo
   |
+  ~
 
 Check that --hidden used with inhibit does not hide every obsolete commit
 We show the log before and after a log -G --hidden, they should be the same
@@ -803,6 +806,7 @@
   $ hg log -G  -r "25::"
   @  25:71eb4f100663 add pk
   |
+  ~
   $ hg up -C 22
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ mkcommit Dk
@@ -816,6 +820,7 @@
   |
   o  25:71eb4f100663 add pk
   |
+  ~
 
 Create a stack (obsolete with succ in dest) -> (not obsolete) -> (not obsolete).
 Rebase the first two revs of the stack onto dest, we expect to see one new
@@ -837,6 +842,7 @@
   |/
   o  25:71eb4f100663 add pk
   |
+  ~
   $ hg prune 28 -s 27
   1 changesets pruned
   $ hg up 25
@@ -857,6 +863,7 @@
   |/
   @  25:71eb4f100663 add pk
   |
+  ~
 
 Rebase the same stack in full on the destination, we expect it to disappear
 and only see the top revision added to destination. We don\'t expect 29 to be
@@ -874,6 +881,7 @@
   |
   @  25:71eb4f100663 add pk
   |
+  ~
 
 Pulling from a inhibit repo to a non-inhibit repo should work
 
--- a/tests/test-obsolete-push.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-obsolete-push.t	Thu May 05 22:13:02 2016 +0200
@@ -25,7 +25,7 @@
   $ echo c > c
   $ hg ci -qAm C c
   $ hg phase --secret --force .
-  $ hg kill 0 1
+  $ hg prune 0 1
   2 changesets pruned
   1 new unstable changesets
   $ glog --hidden
--- a/tests/test-obsolete.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-obsolete.t	Thu May 05 22:13:02 2016 +0200
@@ -457,6 +457,7 @@
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg up 
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1 other heads for branch "default"
   $ hg id -n
   8
 
@@ -508,7 +509,7 @@
 should not rebase extinct changesets
 
 #excluded 'whole rebase set is extinct and ignored.' message not in core
-  $ hg rebase -b '3' -d 4 --traceback
+  $ hg rebase -b '3' -d 4 --traceback --config experimental.rebaseskipobsolete=0
   rebasing 3:0d3f46688ccc "add obsol_c"
   rebasing 8:159dfc9fa5d3 "add obsol_d''" (tip)
   2 new divergent changesets
--- a/tests/test-prune.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-prune.t	Thu May 05 22:13:02 2016 +0200
@@ -194,6 +194,7 @@
 
   $ hg prune 'desc("add cc")' 'desc("add bb")' -s 'desc("add nD")' -s 'desc("add nC")'
   abort: Can't use multiple successors for multiple precursors
+  (use --biject to mark a series as a replacement for another)
   [255]
   $ hg debugobsolete
   9d206ffc875e1bc304590549be293be36821e66c 0 {47d2a3944de8b013de3be9578e8e344ea2e6c097} (Sat Dec 15 00:00:00 1979 +0000) {'user': 'blah'}
--- a/tests/test-sharing.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-sharing.t	Thu May 05 22:13:02 2016 +0200
@@ -89,6 +89,7 @@
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1 other heads for branch "default"
 
 Figure SG03
   $ hg shortlog --hidden -G
@@ -119,6 +120,7 @@
   $ cd ../test-repo
   $ hg update
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1 other heads for branch "default"
   $ hg shortlog --hidden -G
   @  4:de6151c48e1c  draft  fix bug 37
   |
@@ -219,6 +221,7 @@
   |/
   @  1:de6151c48e1c  public  fix bug 37
   |
+  ~
 
 Bob commits a draft changeset, pushes to review repo.
   $ cd ../bob
@@ -294,11 +297,13 @@
   |/
   @  1:de6151c48e1c  public  fix bug 37
   |
+  ~
   $ hg --hidden -R ../public shortlog -G -r 1::
   o  2:540ba8f317e6  public  implement feature X (v3)
   |
   o  1:de6151c48e1c  public  fix bug 37
   |
+  ~
 
 How do things look in the review repo?
   $ cd ../review
@@ -315,6 +320,7 @@
   |/
   @  1:de6151c48e1c  public  fix bug 37
   |
+  ~
 
 Meantime, Alice is back from lunch. While she was away, Bob approved
 her change, so now she can publish it.
@@ -328,6 +334,7 @@
   |/
   o  1:de6151c48e1c  public  fix bug 37
   |
+  ~
   $ hg outgoing -q ../public
   4:cbdfbd5a5db2
   $ hg push ../public
@@ -349,8 +356,10 @@
   $ hg log -G -q -r 'head()'
   o  5:540ba8f317e6
   |
-  | @  4:cbdfbd5a5db2
-  |/
+  ~
+  @  4:cbdfbd5a5db2
+  |
+  ~
   $ hg --hidden shortlog -G -r 1::
   o  5:540ba8f317e6  public  implement feature X (v3)
   |
@@ -362,6 +371,7 @@
   |/
   o  1:de6151c48e1c  public  fix bug 37
   |
+  ~
 
 Alice rebases her draft changeset on top of Bob's public changeset and
 publishes the result.
@@ -401,6 +411,7 @@
   |/
   @  1:de6151c48e1c  public  fix bug 37
   |
+  ~
   $ hg --hidden -R ../public shortlog -G -r 1::
   o  3:a06ec1bf97bd  public  fix bug 15 (v2)
   |
@@ -408,6 +419,7 @@
   |
   o  1:de6151c48e1c  public  fix bug 37
   |
+  ~
   $ cd ..
 
 Setup for "cowboy mode" shared mutable history (to illustrate divergent
@@ -462,6 +474,7 @@
   |/
   o  3:a06ec1bf97bd  public  fix bug 15 (v2)
   |
+  ~
 
 Bob discovers the divergence.
   $ hg pull ../alice
@@ -487,6 +500,7 @@
   |/
   o  3:a06ec1bf97bd  public  fix bug 15 (v2)
   |
+  ~
   $ hg --hidden shortlog -r 'successors(2fe6)'
   6:a360947f6faf  draft  fix bug 24 (v2 by bob)
   7:e3f99ce9d9cd  draft  fix bug 24 (v2 by alice)
@@ -516,6 +530,7 @@
   |/
   o  3:a06ec1bf97bd  public  fix bug 15 (v2)
   |
+  ~
   $ hg --hidden shortlog -r 'precursors(9)'
   6:a360947f6faf  draft  fix bug 24 (v2 by bob)
   7:e3f99ce9d9cd  draft  fix bug 24 (v2 by alice)
--- a/tests/test-split.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-split.t	Thu May 05 22:13:02 2016 +0200
@@ -123,7 +123,7 @@
      summary:     add _a
   
 
-Cannot split a commit with uncommited changes
+Cannot split a commit with uncommitted changes
   $ hg up "desc(_c)"
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo "_cd" > _c
@@ -267,9 +267,9 @@
   |
   o  changeset:   14:aec57822a8ff
   |  user:        test
-  |  date:        Thu Jan 01 00:00:00 1970 +0000
-  |  summary:     split1
-  |
+  ~  date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     split1
+  
   $ hg split <<EOF
   > y
   > y
@@ -313,9 +313,9 @@
   |
   o  changeset:   14:aec57822a8ff
   |  user:        test
-  |  date:        Thu Jan 01 00:00:00 1970 +0000
-  |  summary:     split1
-  |
+  ~  date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     split1
+  
   $ hg book
      bookA                     19:a2b5c9d9b362
    * bookB                     19:a2b5c9d9b362
--- a/tests/test-stabilize-order.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-stabilize-order.t	Thu May 05 22:13:02 2016 +0200
@@ -132,7 +132,7 @@
   no troubled changesets
   [1]
 
-Test behaviour with --any
+Test behavior with --any
 
   $ hg up 8
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
--- a/tests/test-stabilize-result.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-stabilize-result.t	Thu May 05 22:13:02 2016 +0200
@@ -366,6 +366,6 @@
   /!\ * hg up to the parent of the amended changeset (which are named W and Z)
   /!\ * hg revert --all -r X
   /!\ * hg ci -m "same message as the amended changeset" => new cset Y
-  /!\ * hg kill -n Y W Z
+  /!\ * hg prune -n Y W Z
   )
   [255]
--- a/tests/test-tutorial.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-tutorial.t	Thu May 05 22:13:02 2016 +0200
@@ -74,7 +74,7 @@
 Fixing mistake with `hg amend`
 --------------------------------
 
-We are versionning a shopping list
+We are versioning a shopping list
 
   $ cd local
   $ cat  >> shopping << EOF
@@ -207,7 +207,7 @@
 Getting rid of branchy history
 ----------------------------------
 
-While I was working on my list. someone made a change remotly.
+While I was working on my list. someone made a change remotely.
 
   $ cd ../remote
   $ hg up -q
--- a/tests/test-unstable.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-unstable.t	Thu May 05 22:13:02 2016 +0200
@@ -154,9 +154,8 @@
   
 
   $ hg evo --all --any --unstable
-  abort: no support for evolving merge changesets with two obsolete parents yet
-  (Redo the merge and use `hg prune <old> --succ <new>` to obsolete the old one)
-  [255]
+  warning: no support for evolving merge changesets with two obsolete parents yet
+  (Redo the merge (6b4280e33286) and use `hg prune <old> --succ <new>` to obsolete the old one)
   $ hg log -G
   @  5:2db39fda7e2f@default(draft) cprime
   |
--- a/tests/test-userguide.t	Wed Apr 20 16:40:11 2016 -0700
+++ b/tests/test-userguide.t	Thu May 05 22:13:02 2016 +0200
@@ -76,6 +76,7 @@
   |
   @  3:934359450037  draft  implement feature Y
   |
+  ~
 
 example 5: uncommit files at head (figure 4)
   $ echo 'relevant' >> file1.c
@@ -91,6 +92,7 @@
   |/
   o  3:934359450037  draft  implement feature Y
   |
+  ~
   $ hg parents --template '{rev}:{node|short}  {desc|firstline}\n{files}\n'
   6:c8defeecf7a4  fix bug 234
   file1.c
@@ -121,6 +123,7 @@
   |/
   o  6:c8defeecf7a4  draft  fix bug 234
   |
+  ~
   $ hg --hidden log -q -r 'successors(7) | successors(8) | successors(9)'
   10:171c6a79a27b
   $ hg --hidden log -q -r 'precursors(10)'
@@ -156,6 +159,7 @@
   |
   o  10:171c6a79a27b  draft  fix bug 64
   |
+  ~
 
 example 7: amend an older changeset (figures 6, 7)
   $ hg update -q 11
@@ -180,6 +184,7 @@
   |/
   o  10:171c6a79a27b  draft  fix bug 64
   |
+  ~
   $ hg evolve -q --all
   $ hg shortlog -G -r 10::
   @  17:91b4b0f8b5c5  draft  feature 23
@@ -190,6 +195,7 @@
   |
   o  10:171c6a79a27b  draft  fix bug 64
   |
+  ~
 
 setup for example 8: prune an older changeset (figure 8)
   $ echo 'useful' >> file1.c
@@ -207,6 +213,7 @@
   |
   o  17:91b4b0f8b5c5  draft  feature 23
   |
+  ~
 
 example 8: prune an older changeset (figures 8, 9)
   $ hg prune 19
@@ -219,6 +226,7 @@
   |
   o  18:1f33e68b18b9  draft  useful work
   |
+  ~
   $ hg evolve -q --all --any
   $ hg --hidden shortlog -G -r 18::
   @  21:4393e5877437  draft  more work
@@ -229,6 +237,7 @@
   |/
   o  18:1f33e68b18b9  draft  useful work
   |
+  ~
 
 example 9: uncommit files from an older changeset (discard changes)
 (figure 10)
@@ -246,6 +255,7 @@
   |
   o  21:4393e5877437  draft  more work
   |
+  ~
   $ hg uncommit file2.c
   1 new unstable changesets
   $ hg status
@@ -266,6 +276,7 @@
   |/
   o  21:4393e5877437  draft  more work
   |
+  ~
   $ rm file2.c.orig
 
 example 10: uncommit files from an older changeset (keep changes)
@@ -284,6 +295,7 @@
   |
   o  25:0d972d6888e6  draft  fix bug 67
   |
+  ~
   $ hg uncommit file2.c
   1 new unstable changesets
   $ hg status
@@ -300,6 +312,7 @@
   |/
   o  25:0d972d6888e6  draft  fix bug 67
   |
+  ~
   $ hg evolve --all --any
   move:[27] new feature
   atop:[28] fix a bug
@@ -317,3 +330,4 @@
   |/
   o  25:0d972d6888e6  draft  fix bug 67
   |
+  ~