changeset 1747:b0a67ebc464e mercurial-3.8

merge with future 5.5 Test also run on 3.8 with minor cosmetic change. The 'separate' function is not available before 3.9 so we had to drop it.
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
date Fri, 28 Oct 2016 16:16:19 +0200
parents 21c12b09d78f (current diff) 343298df3f26 (diff)
children 83cf722eafc3 e878999e6af4
files tests/test-obsolete-push.t tests/test-obsolete.t tests/test-prune.t tests/test-uncommit.t
diffstat 19 files changed, 450 insertions(+), 371 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Aug 01 22:37:03 2016 +0200
+++ b/.hgtags	Fri Oct 28 16:16:19 2016 +0200
@@ -40,3 +40,4 @@
 c15d6168412f175568dac89e6ee1cd8434fef906 5.2.1
 bd59cc2ee2039c370a0343f683488cde2a106565 5.3.0
 b21ce82e6f7640c2b38506545968650227d67e9b 5.4.0
+2ad40d972a740a613c4c559104166a015b37cac2 5.4.1
--- a/README	Mon Aug 01 22:37:03 2016 +0200
+++ b/README	Fri Oct 28 16:16:19 2016 +0200
@@ -38,7 +38,7 @@
     hg email --to mercurial-devel@mercurial-scm.org --flag evolve-ext --rev '<your patches>'
 
 See also
-http://mercurial-scm.org/wiki/ContributingChanges#Patch_descriptions
+https://mercurial-scm.org/wiki/ContributingChanges#Patch_descriptions
 for guidelines on the patch description.
 
 Please don't forget to update and run the tests when you fix a bug or
@@ -56,6 +56,21 @@
 Changelog
 =========
 
+5.5.0 --
+
+ - The {obsolete} template now yield "obsolete" or "".
+
+5.4.2 --
+
+ - Fix erroneous manifest computation when solving 'bumped' changeset.
+ - split: avoid crash on empty commit (issue5191),
+ - next: improve locking to avoid issue with working copy parent (issue5244)
+ - prev: improve locking to avoid issue with working copy parent (issue5244)
+
+5.4.1 -- 2016-08-01
+
+ - compat with Mercurial 3.9
+
 5.4.0 -- 2016-05-06
 
 - Some collaboration with the topic experimental extensions,
@@ -118,7 +133,7 @@
 - minor documentation cleanup
 - support -i option for `hg amend` if commit supports it (3.4)
 - fix the `debugrecordpruneparents` utility
-- fix some possible crash during command abort (release non-existant transaction)
+- fix some possible crash during command abort (release nonexistent transaction)
 - fix simple4server bug tracker URL
 - compatibility with bookmark API change in future Mercurial 3.5
 - prune no longer move the active bookmark for no reason (issue4559)
@@ -136,7 +151,7 @@
 
 5.1.3 -- 2015-04-20
 
-- discovery: fix misbehaving discovery accros python version
+- discovery: fix misbehaving discovery across python version
 - pull: properly install the bundle2 par generator
   (avoid sending all markers for each pull)
 - commit: avoid potential deadlock (acquires wlock before lock)
@@ -156,7 +171,7 @@
 
 - evolve: explicitly disable bookmark on evolve (issue4432)
 - evolve: don't abort Mercurial on version mismatch
-- comptatibility with mercurial 3.3
+- compatibility with mercurial 3.3
 
 5.0.2 -- 2014-12-14
 
@@ -231,7 +246,7 @@
 
 - fix a bug where evolve were creating changeset with 2 parents on windows
   (fix issues #16, #35 and #42)
-- adds a --obsolete flag to import (requieres Mercurial 3.0)
+- adds a --obsolete flag to import (requires Mercurial 3.0)
 - prune: update to successor rather than parent when pruning '.' with -s
 - fold: add missing --message and --logfile option
 - fold: add squash as an alias
@@ -272,7 +287,7 @@
 3.1.0 -- 2013-02-11
 
 - amend: drop deprecated --change option for amend
-- alias: add a grab aliast to be used instead of graft -O
+- alias: add a grab alias to be used instead of graft -O
 - touch: add a --duplicate option to *not* obsolete the old version
 - touch: fix touching multiple revision at the same time
 - evolve: add a --all option
@@ -350,7 +365,7 @@
 0.6 -- 2012-07-31
 
 - obsolete: change warning output to match mercurial core on
-- qsync: ignore unexistent nodes
+- qsync: ignore nonexistent nodes
 - make compat server both compatible with "dump" and "dump%i" version
 
 0.5 -- 2012-07-16
@@ -364,7 +379,7 @@
 
 0.4.1 -- 2012-07-10
 
-- [convert] properly exclude null successors from convertion
+- [convert] properly exclude null successors from conversion
 - Ignore buggy marker in newerversion
 
 
@@ -385,7 +400,7 @@
 - revset:    add, successors(), allsuccessors(), precursors(), allprecursors(),
              latecomer() and hidden()
 - evolve:    add `prune` alias to `kill`.
-- stabilize: clearly state that stabilize does nto handle conflict
+- stabilize: clearly state that stabilize does not handle conflict
 - template:  add an {obsolete} keyword
 
 0.2.0 -- 2012-06-20
--- a/docs/evolve-faq.rst	Mon Aug 01 22:37:03 2016 +0200
+++ b/docs/evolve-faq.rst	Fri Oct 28 16:16:19 2016 +0200
@@ -116,7 +116,7 @@
 
 For more complexe scenario we recommend the use of the histedit_ extension.
 
-.. _histedit: http://mercurial.selenic.com/wiki/HisteditExtension
+.. _histedit: https://www.mercurial-scm.org/wiki/HisteditExtension
 
 
 Update my current work in progress after a pull
--- a/docs/index.rst	Mon Aug 01 22:37:03 2016 +0200
+++ b/docs/index.rst	Fri Oct 28 16:16:19 2016 +0200
@@ -14,7 +14,7 @@
 
 `evolve`_ is an experimental Mercurial extension for safe mutable history.
 
-.. _`evolve`: http://mercurial.selenic.com/wiki/EvolveExtension
+.. _`evolve`: https://www.mercurial-scm.org/wiki/EvolveExtension
 
 With core Mercurial, changesets are permanent and immutable. You can
 commit new changesets to modify your source code, but you cannot
@@ -99,11 +99,11 @@
 
   * There are still some corner cases that aren't handled yet. If you
     think you have found such a case, please check if it's already
-    described in the Mercurial bug tracker (http://bz.selenic.com).
+    described in the Mercurial bug tracker (https://bz.mercurial-scm.org/).
     Bugs in ``evolve`` are files under component "evolution": use
     `this query`_ to view open bugs in ``evolve``.
 
-.. _`this query`: http://bz.selenic.com/buglist.cgi?component=evolution&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE
+.. _`this query`: https://bz.mercurial-scm.org/buglist.cgi?component=evolution&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE
 
 Installation and setup
 ----------------------
--- a/hgext/directaccess.py	Mon Aug 01 22:37:03 2016 +0200
+++ b/hgext/directaccess.py	Fri Oct 28 16:16:19 2016 +0200
@@ -132,38 +132,35 @@
 
 _listtuple = ('symbol', '_list')
 
+def _ishashsymbol(symbol, maxrev):
+    # Returns true if symbol looks like a hash
+    try:
+        n = int(symbol)
+        if n <= maxrev:
+            # It's a rev number
+            return False
+    except ValueError:
+        pass
+    return hashre.match(symbol)
+
 def gethashsymbols(tree, maxrev):
     # Returns the list of symbols of the tree that look like hashes
     # for example for the revset 3::abe3ff it will return ('abe3ff')
     if not tree:
         return []
 
+    results = []
     if len(tree) == 2 and tree[0] == "symbol":
-        try:
-            n = int(tree[1])
-            # This isn't necessarily a rev number, could be a hash prefix
-            if n > maxrev:
-                return [tree[1]]
-            else:
-                return []
-        except ValueError as e:
-            if hashre.match(tree[1]):
-                return [tree[1]]
-            return []
+        results.append(tree[1])
     elif tree[0] == "func" and tree[1] == _listtuple:
         # the optimiser will group sequence of hash request
-        result = []
-        for entry in tree[2][1].split('\0'):
-            if hashre.match(entry):
-                result.append(entry)
-        return result
+        results += tree[2][1].split('\0')
     elif len(tree) >= 3:
-        results = []
         for subtree in tree[1:]:
             results += gethashsymbols(subtree, maxrev)
+        # return directly, we don't need to filter symbols again
         return results
-    else:
-        return []
+    return [s for s in results if _ishashsymbol(s, maxrev)]
 
 def _posttreebuilthook(orig, tree, repo):
     # This is use to enabled direct hash access
--- a/hgext/evolve.py	Mon Aug 01 22:37:03 2016 +0200
+++ b/hgext/evolve.py	Fri Oct 28 16:16:19 2016 +0200
@@ -19,9 +19,9 @@
     - improves some aspect of the early implementation in Mercurial core
 '''
 
-__version__ = '5.4.0'
-testedwith = '3.4.3 3.5.2 3.6.2 3.7.3 3.8.1'
-buglink = 'http://bz.selenic.com/'
+__version__ = '5.4.1'
+testedwith = '3.4.3 3.5.2 3.6.2 3.7.3 3.8.1 3.9'
+buglink = 'https://bz.mercurial-scm.org/'
 
 
 evolutionhelptext = """
@@ -71,6 +71,7 @@
 import collections
 import socket
 import errno
+import hashlib
 import struct
 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
 
@@ -664,17 +665,11 @@
 
 @eh.templatekw('obsolete')
 def obsoletekw(repo, ctx, templ, **args):
-    """:obsolete: String. The obsolescence level of the node, could be
-    ``stable``, ``unstable``, ``suspended`` or ``extinct``.
+    """:obsolete: String. Whether the changeset is ``obsolete``.
     """
     if ctx.obsolete():
-        if ctx.extinct():
-            return 'extinct'
-        else:
-            return 'suspended'
-    elif ctx.unstable():
-        return 'unstable'
-    return 'stable'
+        return 'obsolete'
+    return ''
 
 @eh.templatekw('troubles')
 def showtroubles(repo, ctx, **args):
@@ -963,28 +958,25 @@
     tr = repo.currenttransaction()
     assert tr is not None
     try:
-        try:
-            r = _evolvemerge(repo, orig, dest, pctx, keepbranch)
-            if r[-1]:  #some conflict
-                raise error.Abort(
-                        'unresolved merge conflicts (see hg help resolve)')
-            nodenew = _relocatecommit(repo, orig, commitmsg)
-        except error.Abort as exc:
-            repo.dirstate.beginparentchange()
-            repo.setparents(repo['.'].node(), nullid)
-            writedirstate(repo.dirstate, tr)
-            # fix up dirstate for copies and renames
-            copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
-            repo.dirstate.endparentchange()
-            class LocalMergeFailure(MergeFailure, exc.__class__):
-                pass
-            exc.__class__ = LocalMergeFailure
-            tr.close() # to keep changes in this transaction (e.g. dirstate)
-            raise
-        oldbookmarks = repo.nodebookmarks(nodesrc)
-        _finalizerelocate(repo, orig, dest, nodenew, tr)
-    finally:
-        pass # TODO: remove this redundant try/finally block
+        r = _evolvemerge(repo, orig, dest, pctx, keepbranch)
+        if r[-1]:  #some conflict
+            raise error.Abort(
+                    'unresolved merge conflicts (see hg help resolve)')
+        nodenew = _relocatecommit(repo, orig, commitmsg)
+    except error.Abort as exc:
+        repo.dirstate.beginparentchange()
+        repo.setparents(repo['.'].node(), nullid)
+        writedirstate(repo.dirstate, tr)
+        # fix up dirstate for copies and renames
+        copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
+        repo.dirstate.endparentchange()
+        class LocalMergeFailure(MergeFailure, exc.__class__):
+            pass
+        exc.__class__ = LocalMergeFailure
+        tr.close() # to keep changes in this transaction (e.g. dirstate)
+        raise
+    oldbookmarks = repo.nodebookmarks(nodesrc)
+    _finalizerelocate(repo, orig, dest, nodenew, tr)
     return nodenew
 
 def _bookmarksupdater(repo, oldid, tr):
@@ -1023,7 +1015,7 @@
 ### dirstate compatibility layer < hg 3.6
 
 def writedirstate(dirstate, tr):
-    if dirstate.write.func_defaults is not None: # mercurial 3.6 and above
+    if dirstate.write.func_code.co_argcount != 1: # mercurial 3.6 and above
         return dirstate.write(tr)
     return dirstate.write()
 
@@ -1793,14 +1785,18 @@
             raise error.Abort('no evolve to continue')
         orig = repo[state['current']]
         # XXX This is a terrible terrible hack, please get rid of it.
-        repo.opener.write('graftstate', orig.hex() + '\n')
+        lock = repo.wlock()
         try:
-            graftcmd = commands.table['graft'][0]
-            ret = graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
-            _evolvestatedelete(repo)
-            return ret
+            repo.opener.write('graftstate', orig.hex() + '\n')
+            try:
+                graftcmd = commands.table['graft'][0]
+                ret = graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
+                _evolvestatedelete(repo)
+                return ret
+            finally:
+                util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
         finally:
-            util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
+            lock.release()
     cmdutil.bailifchanged(repo)
 
 
@@ -1993,73 +1989,70 @@
     tr = repo.currenttransaction()
     assert tr is not None
     bmupdate = _bookmarksupdater(repo, bumped.node(), tr)
-    try:
-        if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)):
-            # Need to rebase the changeset at the right place
-            repo.ui.status(
-                _('rebasing to destination parent: %s\n') % prec.p1())
-            try:
-                tmpid = relocate(repo, bumped, prec.p1())
-                if tmpid is not None:
-                    tmpctx = repo[tmpid]
-                    obsolete.createmarkers(repo, [(bumped, (tmpctx,))])
-            except MergeFailure:
-                repo.opener.write('graftstate', bumped.hex() + '\n')
-                repo.ui.write_err(_('evolution failed!\n'))
-                repo.ui.write_err(
-                    _('fix conflict and run "hg evolve --continue"\n'))
-                raise
-        # Create the new commit context
-        repo.ui.status(_('computing new diff\n'))
-        files = set()
-        copied = copies.pathcopies(prec, bumped)
-        precmanifest = prec.manifest()
-        # 3.3.2 needs a list.
-        # future 3.4 don't detect the size change during iteration
-        # this is fishy
-        for key, val in list(bumped.manifest().iteritems()):
-            precvalue = precmanifest.get(key, None)
-            if precvalue is not None:
-                del precmanifest[key]
-            if precvalue != val:
-                files.add(key)
-        files.update(precmanifest)  # add missing files
-        # commit it
-        if files: # something to commit!
-            def filectxfn(repo, ctx, path):
-                if path in bumped:
-                    fctx = bumped[path]
-                    flags = fctx.flags()
-                    mctx = memfilectx(repo, fctx.path(), fctx.data(),
-                                      islink='l' in flags,
-                                      isexec='x' in flags,
-                                      copied=copied.get(path))
-                    return mctx
-                return None
-            text = 'bumped update to %s:\n\n' % prec
-            text += bumped.description()
-
-            new = context.memctx(repo,
-                                 parents=[prec.node(), node.nullid],
-                                 text=text,
-                                 files=files,
-                                 filectxfn=filectxfn,
-                                 user=bumped.user(),
-                                 date=bumped.date(),
-                                 extra=bumped.extra())
-
-            newid = repo.commitctx(new)
-        if newid is None:
-            obsolete.createmarkers(repo, [(tmpctx, ())])
-            newid = prec.node()
-        else:
-            phases.retractboundary(repo, tr, bumped.phase(), [newid])
-            obsolete.createmarkers(repo, [(tmpctx, (repo[newid],))],
-                                   flag=obsolete.bumpedfix)
-        bmupdate(newid)
-        repo.ui.status(_('committed as %s\n') % node.short(newid))
-    finally:
-        pass # TODO: remove this redundant try/finally block
+    if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)):
+        # Need to rebase the changeset at the right place
+        repo.ui.status(
+            _('rebasing to destination parent: %s\n') % prec.p1())
+        try:
+            tmpid = relocate(repo, bumped, prec.p1())
+            if tmpid is not None:
+                tmpctx = repo[tmpid]
+                obsolete.createmarkers(repo, [(bumped, (tmpctx,))])
+        except MergeFailure:
+            repo.opener.write('graftstate', bumped.hex() + '\n')
+            repo.ui.write_err(_('evolution failed!\n'))
+            repo.ui.write_err(
+                _('fix conflict and run "hg evolve --continue"\n'))
+            raise
+    # Create the new commit context
+    repo.ui.status(_('computing new diff\n'))
+    files = set()
+    copied = copies.pathcopies(prec, bumped)
+    precmanifest = prec.manifest().copy()
+    # 3.3.2 needs a list.
+    # future 3.4 don't detect the size change during iteration
+    # this is fishy
+    for key, val in list(bumped.manifest().iteritems()):
+        precvalue = precmanifest.get(key, None)
+        if precvalue is not None:
+            del precmanifest[key]
+        if precvalue != val:
+            files.add(key)
+    files.update(precmanifest)  # add missing files
+    # commit it
+    if files: # something to commit!
+        def filectxfn(repo, ctx, path):
+            if path in bumped:
+                fctx = bumped[path]
+                flags = fctx.flags()
+                mctx = memfilectx(repo, fctx.path(), fctx.data(),
+                                  islink='l' in flags,
+                                  isexec='x' in flags,
+                                  copied=copied.get(path))
+                return mctx
+            return None
+        text = 'bumped update to %s:\n\n' % prec
+        text += bumped.description()
+
+        new = context.memctx(repo,
+                             parents=[prec.node(), node.nullid],
+                             text=text,
+                             files=files,
+                             filectxfn=filectxfn,
+                             user=bumped.user(),
+                             date=bumped.date(),
+                             extra=bumped.extra())
+
+        newid = repo.commitctx(new)
+    if newid is None:
+        obsolete.createmarkers(repo, [(tmpctx, ())])
+        newid = prec.node()
+    else:
+        phases.retractboundary(repo, tr, bumped.phase(), [newid])
+        obsolete.createmarkers(repo, [(tmpctx, (repo[newid],))],
+                               flag=obsolete.bumpedfix)
+    bmupdate(newid)
+    repo.ui.status(_('committed as %s\n') % node.short(newid))
     # reroute the working copy parent to the new changeset
     repo.dirstate.beginparentchange()
     repo.dirstate.setparents(newid, node.nullid)
@@ -2220,57 +2213,63 @@
     """update to parent revision
 
     Displays the summary line of the destination for clarity."""
-    wkctx = repo[None]
-    wparents = wkctx.parents()
+    wlock = None
     dryrunopt = opts['dry_run']
-    if len(wparents) != 1:
-        raise error.Abort('merge in progress')
-    if not opts['merge']:
-        try:
-            cmdutil.bailifchanged(repo)
-        except error.Abort as exc:
-            exc.hint = _('do you want --merge?')
-            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 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
-        if dryrunopt:
-            ui.write(('hg update %s;\n' % p.rev()))
-            if shouldmove:
-                ui.write(('hg bookmark %s -r %s;\n' % (bm, p.rev())))
+    if not dryrunopt:
+        wlock = repo.wlock()
+    try:
+        wkctx = repo[None]
+        wparents = wkctx.parents()
+        if len(wparents) != 1:
+            raise error.Abort('merge in progress')
+        if not opts['merge']:
+            try:
+                cmdutil.bailifchanged(repo)
+            except error.Abort as exc:
+                exc.hint = _('do you want --merge?')
+                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 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
+            if dryrunopt:
+                ui.write(('hg update %s;\n' % p.rev()))
+                if shouldmove:
+                    ui.write(('hg bookmark %s -r %s;\n' % (bm, p.rev())))
+            else:
+                ret = hg.update(repo, p.rev())
+                if not ret:
+                    tr = lock = None
+                    try:
+                        lock = repo.lock()
+                        tr = repo.transaction('previous')
+                        if shouldmove:
+                            repo._bookmarks[bm] = p.node()
+                            repo._bookmarks.recordchange(tr)
+                        else:
+                            bmdeactivate(repo)
+                        tr.close()
+                    finally:
+                        lockmod.release(tr, lock)
+
+            displayer.show(p)
+            return 0
         else:
-            ret = hg.update(repo, p.rev())
-            if not ret:
-                tr = lock = None
-                wlock = repo.wlock()
-                try:
-                    lock = repo.lock()
-                    tr = repo.transaction('previous')
-                    if shouldmove:
-                        repo._bookmarks[bm] = p.node()
-                        repo._bookmarks.recordchange(tr)
-                    else:
-                        bmdeactivate(repo)
-                    tr.close()
-                finally:
-                    lockmod.release(tr, lock, wlock)
-        displayer.show(p)
-        return 0
-    else:
-        for p in parents:
-            displayer.show(p)
-        ui.warn(_('multiple parents, explicitly update to one\n'))
-        return 1
+            for p in parents:
+                displayer.show(p)
+            ui.warn(_('multiple parents, explicitly update to one\n'))
+            return 1
+    finally:
+        lockmod.release(wlock)
 
 @command('^next',
          [('B', 'move-bookmark', False,
@@ -2288,91 +2287,96 @@
 
     Displays the summary line of the destination for clarity.
     """
-    wkctx = repo[None]
-    wparents = wkctx.parents()
+    wlock = None
     dryrunopt = opts['dry_run']
-    if len(wparents) != 1:
-        raise error.Abort('merge in progress')
-    if not opts['merge']:
-        try:
-            cmdutil.bailifchanged(repo)
-        except error.Abort as exc:
-            exc.hint = _('do you want --merge?')
-            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]
-        bm = bmactive(repo)
-        shouldmove = opts.get('move_bookmark') and bm is not None
-        if dryrunopt:
-            ui.write(('hg update %s;\n' % c.rev()))
-            if shouldmove:
-                ui.write(('hg bookmark %s -r %s;\n' % (bm, c.rev())))
+    if not dryrunopt:
+        wlock = repo.wlock()
+    try:
+        wkctx = repo[None]
+        wparents = wkctx.parents()
+        if len(wparents) != 1:
+            raise error.Abort('merge in progress')
+        if not opts['merge']:
+            try:
+                cmdutil.bailifchanged(repo)
+            except error.Abort as exc:
+                exc.hint = _('do you want --merge?')
+                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]
+            bm = bmactive(repo)
+            shouldmove = opts.get('move_bookmark') and bm is not None
+            if dryrunopt:
+                ui.write(('hg update %s;\n' % c.rev()))
+                if shouldmove:
+                    ui.write(('hg bookmark %s -r %s;\n' % (bm, c.rev())))
+            else:
+                ret = hg.update(repo, c.rev())
+                if not ret:
+                    lock = tr = None
+                    try:
+                        lock = repo.lock()
+                        tr = repo.transaction('next')
+                        if shouldmove:
+                            repo._bookmarks[bm] = c.node()
+                            repo._bookmarks.recordchange(tr)
+                        else:
+                            bmdeactivate(repo)
+                        tr.close()
+                    finally:
+                        lockmod.release(tr, lock)
+            displayer.show(c)
+            result = 0
+        elif children:
+            ui.warn(_("ambigious next changeset:\n"))
+            for c in children:
+                displayer.show(c)
+            ui.warn(_('explicitly update to one of them\n'))
+            result = 1
         else:
-            ret = hg.update(repo, c.rev())
-            if not ret:
-                lock = tr = None
-                wlock = repo.wlock()
-                try:
-                    lock = repo.lock()
-                    tr = repo.transaction('next')
-                    if shouldmove:
-                        repo._bookmarks[bm] = c.node()
-                        repo._bookmarks.recordchange(tr)
-                    else:
-                        bmdeactivate(repo)
-                    tr.close()
-                finally:
-                    lockmod.release(tr, lock, wlock)
-        displayer.show(c)
-        result = 0
-    elif children:
-        ui.warn(_("ambigious next changeset:\n"))
-        for c in children:
-            displayer.show(c)
-        ui.warn(_('explicitly update to one of them\n'))
-        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:
-            if filtered:
-                ui.warn(_('no children on topic "%s"\n') % topic)
-                ui.warn(_('do you want --no-topic\n'))
+            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:
+                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')
+                    ui.warn(msg % len(aspchildren))
+                result = 1
+            elif 1 < len(aspchildren):
+                ui.warn(_("ambigious next (unstable) changeset:\n"))
+                for c in aspchildren:
+                    displayer.show(repo[c])
+                ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
+                return 1
             else:
-                ui.warn(_('no children\n'))
-            if aspchildren:
-                msg = _('(%i unstable changesets to be evolved here, '
-                        'do you want --evolve?)\n')
-                ui.warn(msg % len(aspchildren))
-            result = 1
-        elif 1 < len(aspchildren):
-            ui.warn(_("ambigious next (unstable) changeset:\n"))
-            for c in aspchildren:
-                displayer.show(repo[c])
-            ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
+                cmdutil.bailifchanged(repo)
+                result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
+                                   False, lambda:None, category='unstable')
+                if not result:
+                    ui.status(_('working directory now at %s\n') % repo['.'])
+                return result
             return 1
-        else:
-            cmdutil.bailifchanged(repo)
-            result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
-                               False, lambda:None, category='unstable')
-            if not result:
-                ui.status(_('working directory now at %s\n') % repo['.'])
-            return result
-        return 1
-    return result
+        return result
+    finally:
+        lockmod.release(wlock)
 
 def _reachablefrombookmark(repo, revs, bookmarks):
     """filter revisions and bookmarks reachable from the given bookmark
@@ -2939,11 +2943,12 @@
             else:
                 ui.status(_("no more change to split\n"))
 
-        tip = repo[newcommits[-1]]
-        bmupdate(tip.node())
-        if bookactive is not None:
-            bmactivate(repo, bookactive)
-        obsolete.createmarkers(repo, [(repo[r], newcommits)])
+        if newcommits:
+            tip = repo[newcommits[-1]]
+            bmupdate(tip.node())
+            if bookactive is not None:
+                bmactivate(repo, bookactive)
+            obsolete.createmarkers(repo, [(repo[r], newcommits)])
         tr.close()
     finally:
         lockmod.release(tr, lock, wlock)
@@ -3859,7 +3864,7 @@
     for i in unfi:
         ctx = unfi[i]
         entry = 0
-        sha = util.sha1()
+        sha = hashlib.sha1()
         # add data from p1
         for p in ctx.parents():
             p = p.rev()
--- a/hgext/simple4server.py	Mon Aug 01 22:37:03 2016 +0200
+++ b/hgext/simple4server.py	Fri Oct 28 16:16:19 2016 +0200
@@ -8,11 +8,12 @@
 For client side usages it is recommended to use the evolve extension for
 improved user interface.'''
 
-testedwith = '3.3.3 3.4-rc'
-buglink = 'http://bz.selenic.com/'
+testedwith = '3.3 3.4-rc'
+buglink = 'https://bz.mercurial-scm.org/'
 
 import mercurial.obsolete
 
+import hashlib
 import struct
 from mercurial import util
 from mercurial import wireproto
@@ -192,7 +193,7 @@
     for i in unfi:
         ctx = unfi[i]
         entry = 0
-        sha = util.sha1()
+        sha = hashlib.sha1()
         # add data from p1
         for p in ctx.parents():
             p = p.rev()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/fake-editor.sh	Fri Oct 28 16:16:19 2016 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+sleep 5
+echo "new desc" >> $1
--- a/tests/test-evolve-topic.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-evolve-topic.t	Fri Oct 28 16:16:19 2016 +0200
@@ -76,6 +76,8 @@
   switching to topic foo
   0 files updated, 0 files merged, 4 files removed, 0 files unresolved
   $ hg topic -l 
+  ### topic: foo (?)
+  ### branch: default (?)
   t4@ add fff (current)
   t3: add eee
   t2: add ddd
--- a/tests/test-evolve.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-evolve.t	Fri Oct 28 16:16:19 2016 +0200
@@ -112,13 +112,13 @@
 test kill and immutable changeset
 
   $ hg log -r 1 --template '{rev} {phase} {obsolete}\n'
-  1 public stable
+  1 public 
   $ hg prune 1
   abort: cannot prune immutable changeset: 7c3bad9141dc
   (see "hg help phases" for details)
   [255]
   $ hg log -r 1 --template '{rev} {phase} {obsolete}\n'
-  1 public stable
+  1 public 
 
 test simple kill
 
@@ -377,8 +377,8 @@
   recreate:[8] another feature that rox
   atop:[7] another feature (child of ba0ec09b1bab)
   computing new diff
-  committed as 2d8c5414e9f0
-  working directory is now at 2d8c5414e9f0
+  committed as 6707c5e1c49d
+  working directory is now at 6707c5e1c49d
   $ hg glog
   @  9	feature-B: bumped update to 99833d22b0c6: - test
   |
@@ -437,7 +437,7 @@
   move:[11] dansk 3!
   atop:[14] dansk 2!
   merging main-file-1
-  working directory is now at 536984593824
+  working directory is now at 68557e4f0048
   $ hg glog
   @  15	: dansk 3! - test
   |
@@ -598,7 +598,7 @@
   (use 'hg resolve' and 'hg graft --continue')
   [255]
   $ hg log -r7 --template '{rev}:{node|short} {obsolete}\n'
-  7:a5bfd90a2f29 stable
+  7:a5bfd90a2f29 
   $ echo 3 > 1
   $ hg resolve -m 1
   (no more unresolved files)
@@ -810,9 +810,9 @@
   2 changesets folded
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ glog
-  @  16:d1297ecc971f@default(draft) Folding with custom commit message
+  @  16:98cb758db56d@default(draft) Folding with custom commit message
   |
-  o  13:27b934eaf1f9@default(draft) dansk!
+  o  13:0a2f9b959bb4@default(draft) dansk!
   |
   o  7:99833d22b0c6@default(public) another feature (child of ba0ec09b1bab)
   |
@@ -829,7 +829,7 @@
   2 changesets folded
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg qlog
-  17 - 0b1eca0e871b A longer
+  17 - a00182c58888 A longer
                     commit message (draft)
   7 - 99833d22b0c6 another feature (child of ba0ec09b1bab) (public)
   6 - ba0ec09b1bab a nifty feature (public)
--- a/tests/test-inhibit.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-inhibit.t	Fri Oct 28 16:16:19 2016 +0200
@@ -375,6 +375,21 @@
   cf5c4f4554ce
   2db36d8066ff
 
+Test directaccess only takes hashes
+
+  $ HOOKPATH=$TESTTMP/printexplicitaccess.py
+  $ cat >> $HOOKPATH <<EOF
+  > def hook(ui, repo, **kwds):
+  >     for i in sorted(repo._explicitaccess):
+  >         ui.write('directaccess: %s\n' % i)
+  > EOF
+
+  $ hg log -r 1 -r 2 -r 2db36d8066f -T '{rev}\n' --config hooks.post-log=python:$HOOKPATH:hook
+  1
+  2
+  3
+  directaccess: 3
+
 With severals hidden sha, rebase of one hidden stack onto another one:
   $ hg update -C 0
   0 files updated, 0 files merged, 4 files removed, 0 files unresolved
--- a/tests/test-obsolete-push.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-obsolete-push.t	Fri Oct 28 16:16:19 2016 +0200
@@ -29,11 +29,11 @@
   2 changesets pruned
   1 new unstable changesets
   $ glog --hidden
-  @  2:244232c2222a@default(unstable/secret) C
+  @  2:244232c2222a@default(/secret) C
   |
-  | x  1:6c81ed0049f8@default(extinct/draft) B
+  | x  1:6c81ed0049f8@default(obsolete/draft) B
   |/
-  x  0:1994f17a630e@default(suspended/draft) A
+  x  0:1994f17a630e@default(obsolete/draft) A
   
   $ hg init ../clone
   $ cat >  ../clone/.hg/hgrc <<EOF
@@ -43,4 +43,4 @@
   $ hg outgoing ../clone --template "$template"
   comparing with ../clone
   searching for changes
-  0:1994f17a630e@default(suspended/draft) A
+  0:1994f17a630e@default(obsolete/draft) A
--- a/tests/test-obsolete.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-obsolete.t	Fri Oct 28 16:16:19 2016 +0200
@@ -150,19 +150,19 @@
 
 Test obsolete keyword
 
-  $ hg log -G --template '{rev}:{node|short}@{branch}({obsolete}/{phase}) {desc|firstline}\n' \
-  >   --hidden
-  @  5:a7a6f2b5d8a5@default(unstable/draft) add d
+  $ hg --hidden log -G \
+  >  --template '{rev}:{node|short}@{branch}({obsolete}/{phase}) {desc|firstline}\n'
+  @  5:a7a6f2b5d8a5@default(/draft) add d
   |
-  | o  4:725c380fe99b@default(stable/draft) add obsol_c'
+  | o  4:725c380fe99b@default(/draft) add obsol_c'
   | |
-  x |  3:0d3f46688ccc@default(suspended/draft) add obsol_c
+  x |  3:0d3f46688ccc@default(obsolete/draft) add obsol_c
   |/
-  | x  2:4538525df7e2@default(extinct/draft) add c
+  | x  2:4538525df7e2@default(obsolete/draft) add c
   |/
-  o  1:7c3bad9141dc@default(stable/draft) add b
+  o  1:7c3bad9141dc@default(/draft) add b
   |
-  o  0:1f0dee641bb7@default(stable/public) add a
+  o  0:1f0dee641bb7@default(/public) add a
   
 
 Test communication of obsolete relation with a compatible client
--- a/tests/test-prev-next.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-prev-next.t	Fri Oct 28 16:16:19 2016 +0200
@@ -206,3 +206,34 @@
   move:[5] added d
   atop:[6] added b (3)
   working directory is now at 47ea25be8aea
+
+prev and next should lock properly against other commands
+
+  $ hg init repo
+  $ cd repo
+  $ HGEDITOR=${TESTDIR}/fake-editor.sh
+  $ echo hi > foo
+  $ hg ci -Am 'one'
+  adding foo
+  $ echo bye > foo
+  $ hg ci -Am 'two'
+
+  $ hg amend --edit &
+  $ sleep 1
+  $ hg prev
+  waiting for lock on working directory of $TESTTMP/repo held by '*' (glob)
+  got lock after [4-6] seconds (re)
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  [0] one
+  $ wait
+
+  $ hg amend --edit &
+  $ sleep 1
+  $ hg next --evolve
+  waiting for lock on working directory of $TESTTMP/repo held by '*' (glob)
+  1 new unstable changesets
+  got lock after [4-6] seconds (re)
+  move:[2] two
+  atop:[3] one
+  working directory now at a7d885c75614
+  $ wait
--- a/tests/test-prune.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-prune.t	Fri Oct 28 16:16:19 2016 +0200
@@ -21,15 +21,15 @@
   $ mkcommit e
   $ hg bookmarks BABAR
   $ hg log -G
-  @  4:9d206ffc875e[BABAR] (stable/draft) add e
+  @  4:9d206ffc875e[BABAR] (/draft) add e
   |
-  o  3:47d2a3944de8[] (stable/draft) add d
+  o  3:47d2a3944de8[] (/draft) add d
   |
-  o  2:4538525df7e2[] (stable/draft) add c
+  o  2:4538525df7e2[] (/draft) add c
   |
-  o  1:7c3bad9141dc[] (stable/draft) add b
+  o  1:7c3bad9141dc[] (/draft) add b
   |
-  o  0:1f0dee641bb7[] (stable/public) add a
+  o  0:1f0dee641bb7[] (/public) add a
   
 
 Check arguments exclusive to each other
@@ -109,23 +109,23 @@
   $ mkcommit nE
 
   $ hg log -G
-  @  12:6e8148413dd5[] (stable/draft) add nE
+  @  12:6e8148413dd5[] (/draft) add nE
   |
-  o  11:8ee176ff1d4b[] (stable/draft) add nD
+  o  11:8ee176ff1d4b[] (/draft) add nD
   |
-  o  10:aa96dc3f04c2[] (stable/draft) add nC
+  o  10:aa96dc3f04c2[] (/draft) add nC
   |
-  o  9:6f6f25e4f748[] (stable/draft) add nB
+  o  9:6f6f25e4f748[] (/draft) add nB
   |
-  | o  8:bb5e90a7ea1f[] (stable/draft) add ee
+  | o  8:bb5e90a7ea1f[] (/draft) add ee
   | |
-  | o  7:00ded550b1e2[] (stable/draft) add dd
+  | o  7:00ded550b1e2[] (/draft) add dd
   | |
-  | o  6:354011cd103f[] (stable/draft) add cc
+  | o  6:354011cd103f[] (/draft) add cc
   | |
-  | o  5:814c38b95e72[] (stable/draft) add bb
+  | o  5:814c38b95e72[] (/draft) add bb
   |/
-  o  0:1f0dee641bb7[BABAR] (stable/public) add a
+  o  0:1f0dee641bb7[BABAR] (/public) add a
   
 
 one old, one new
@@ -143,21 +143,21 @@
   47d2a3944de8b013de3be9578e8e344ea2e6c097 0 {4538525df7e2b9f09423636c61ef63a4cb872a2d} (*) {'user': 'test'} (glob)
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 (*) {'user': 'test'} (glob)
   $ hg log -G
-  @  12:6e8148413dd5[] (stable/draft) add nE
+  @  12:6e8148413dd5[] (/draft) add nE
   |
-  o  11:8ee176ff1d4b[] (stable/draft) add nD
+  o  11:8ee176ff1d4b[] (/draft) add nD
   |
-  o  10:aa96dc3f04c2[] (stable/draft) add nC
+  o  10:aa96dc3f04c2[] (/draft) add nC
   |
-  o  9:6f6f25e4f748[] (stable/draft) add nB
+  o  9:6f6f25e4f748[] (/draft) add nB
   |
-  | o  7:00ded550b1e2[] (stable/draft) add dd
+  | o  7:00ded550b1e2[] (/draft) add dd
   | |
-  | o  6:354011cd103f[] (stable/draft) add cc
+  | o  6:354011cd103f[] (/draft) add cc
   | |
-  | o  5:814c38b95e72[] (stable/draft) add bb
+  | o  5:814c38b95e72[] (/draft) add bb
   |/
-  o  0:1f0dee641bb7[BABAR] (stable/public) add a
+  o  0:1f0dee641bb7[BABAR] (/public) add a
   
 
 one old, two new
@@ -175,19 +175,19 @@
   bb5e90a7ea1f3b4b38b23150a4a597b6146d70ef 6e8148413dd541855b72a920a90c06fca127c7e7 0 (*) {'user': 'test'} (glob)
   00ded550b1e28bba454bd34cec1269d22cf3ef25 aa96dc3f04c2c2341fe6880aeb6dc9fbffff9ef9 8ee176ff1d4b2034ce51e3efc579c2de346b631d 0 (*) {'user': 'test'} (glob)
   $ hg log -G
-  @  12:6e8148413dd5[] (stable/draft) add nE
+  @  12:6e8148413dd5[] (/draft) add nE
   |
-  o  11:8ee176ff1d4b[] (stable/draft) add nD
+  o  11:8ee176ff1d4b[] (/draft) add nD
   |
-  o  10:aa96dc3f04c2[] (stable/draft) add nC
+  o  10:aa96dc3f04c2[] (/draft) add nC
   |
-  o  9:6f6f25e4f748[] (stable/draft) add nB
+  o  9:6f6f25e4f748[] (/draft) add nB
   |
-  | o  6:354011cd103f[] (stable/draft) add cc
+  | o  6:354011cd103f[] (/draft) add cc
   | |
-  | o  5:814c38b95e72[] (stable/draft) add bb
+  | o  5:814c38b95e72[] (/draft) add bb
   |/
-  o  0:1f0dee641bb7[BABAR] (stable/public) add a
+  o  0:1f0dee641bb7[BABAR] (/public) add a
   
 
 two old, two new (should be denied)
@@ -373,56 +373,56 @@
   (leaving bookmark rg)
   $ hg bookmark r10
   $ hg log -G
-  o  15:cd0038e05e1b[rg] (stable/draft) add rg
+  o  15:cd0038e05e1b[rg] (/draft) add rg
   |
-  | x  14:43227190fef8[] (extinct/draft) r14
+  | x  14:43227190fef8[] (obsolete/draft) r14
   | |
-  | | x  13:b4594d867745[] (extinct/draft) r13
+  | | x  13:b4594d867745[] (obsolete/draft) r13
   | | |
-  | | | x  12:e46a4836065c[] (extinct/draft) r12
+  | | | x  12:e46a4836065c[] (obsolete/draft) r12
   | | |/
-  | | o  11:bab5d5bf48bd[] (stable/draft) r11
+  | | o  11:bab5d5bf48bd[] (/draft) r11
   | |/
-  +---@  10:ff43616e5d0f[B r10] (stable/draft) r10
+  +---@  10:ff43616e5d0f[B r10] (/draft) r10
   | |
-  o |  8:d62d843c9a01[] (stable/draft) r8
+  o |  8:d62d843c9a01[] (/draft) r8
   | |
-  o |  7:e7d9710d9fc6[] (stable/draft) r7
+  o |  7:e7d9710d9fc6[] (/draft) r7
   |/
-  o    3:2b6d669947cd[] (stable/draft) r3
+  o    3:2b6d669947cd[] (/draft) r3
   |\
-  | o  2:fa942426a6fd[] (stable/draft) r2
+  | o  2:fa942426a6fd[] (/draft) r2
   | |
-  o |  1:66f7d451a68b[] (stable/draft) r1
+  o |  1:66f7d451a68b[] (/draft) r1
   |/
-  o  0:1ea73414a91b[] (stable/draft) r0
+  o  0:1ea73414a91b[] (/draft) r0
   
   $ hg prune 11
   1 changesets pruned
   $ hg log -G
-  o  15:cd0038e05e1b[rg] (stable/draft) add rg
+  o  15:cd0038e05e1b[rg] (/draft) add rg
   |
-  | x  14:43227190fef8[] (extinct/draft) r14
+  | x  14:43227190fef8[] (obsolete/draft) r14
   | |
-  | | x  13:b4594d867745[] (extinct/draft) r13
+  | | x  13:b4594d867745[] (obsolete/draft) r13
   | | |
-  | | | x  12:e46a4836065c[] (extinct/draft) r12
+  | | | x  12:e46a4836065c[] (obsolete/draft) r12
   | | |/
-  | | x  11:bab5d5bf48bd[] (extinct/draft) r11
+  | | x  11:bab5d5bf48bd[] (obsolete/draft) r11
   | |/
-  +---@  10:ff43616e5d0f[B r10] (stable/draft) r10
+  +---@  10:ff43616e5d0f[B r10] (/draft) r10
   | |
-  o |  8:d62d843c9a01[] (stable/draft) r8
+  o |  8:d62d843c9a01[] (/draft) r8
   | |
-  o |  7:e7d9710d9fc6[] (stable/draft) r7
+  o |  7:e7d9710d9fc6[] (/draft) r7
   |/
-  o    3:2b6d669947cd[] (stable/draft) r3
+  o    3:2b6d669947cd[] (/draft) r3
   |\
-  | o  2:fa942426a6fd[] (stable/draft) r2
+  | o  2:fa942426a6fd[] (/draft) r2
   | |
-  o |  1:66f7d451a68b[] (stable/draft) r1
+  o |  1:66f7d451a68b[] (/draft) r1
   |/
-  o  0:1ea73414a91b[] (stable/draft) r0
+  o  0:1ea73414a91b[] (/draft) r0
   
   $ hg book CELESTE
   $ hg prune -r . --keep
--- a/tests/test-simple4server.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-simple4server.t	Fri Oct 28 16:16:19 2016 +0200
@@ -9,6 +9,8 @@
   > publish = False
   > [experimental]
   > bundle2-exp=False
+  > [devel]
+  > legacy.exchange=bundle1
   > [extensions]
   > EOF
 
--- a/tests/test-split.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-split.t	Fri Oct 28 16:16:19 2016 +0200
@@ -378,3 +378,10 @@
   (use either `hg split <rs>` or `hg split --rev <rs>`, not both)
   [255]
 
+Split empty commit (issue5191)
+  $ hg branch new-branch
+  marked working directory as branch new-branch
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg commit -m "empty"
+  $ hg split
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-stabilize-result.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-stabilize-result.t	Fri Oct 28 16:16:19 2016 +0200
@@ -176,10 +176,10 @@
   perform evolve? [Ny] y
   rebasing to destination parent: 66719795a494
   computing new diff
-  committed as (a7cabd7bd9c2|671b9d7eeaec) (re)
-  working directory is now at (a7cabd7bd9c2|671b9d7eeaec) (re)
+  committed as c2c1151aa854
+  working directory is now at c2c1151aa854
   $ glog
-  @  14:(a7cabd7bd9c2|671b9d7eeaec)@default\(draft\) bk:\[\] bumped update to 1cf0aacfd363: (re)
+  @  14:c2c1151aa854@default(draft) bk:[] bumped update to 1cf0aacfd363:
   |
   | o  9:7bc2f5967f5e@default(draft) bk:[] add c
   | |
--- a/tests/test-uncommit.t	Mon Aug 01 22:37:03 2016 +0200
+++ b/tests/test-uncommit.t	Fri Oct 28 16:16:19 2016 +0200
@@ -118,13 +118,13 @@
 Add a couple of bookmarks
 
   $ glog --hidden
-  @  3:5eb72dbe0cb4@bar(stable/draft) touncommit
+  @  3:5eb72dbe0cb4@bar(/draft) touncommit
   |
-  o    2:f63b90038565@default(stable/draft) merge
+  o    2:f63b90038565@default(/draft) merge
   |\
-  | o  1:f15c744d48e8@default(stable/draft) addmore
+  | o  1:f15c744d48e8@default(/draft) addmore
   |
-  o  0:07f494440405@default(stable/draft) adda
+  o  0:07f494440405@default(/draft) adda
   
   $ hg bookmark -r 2 unrelated
   $ hg bookmark touncommit-bm
@@ -217,15 +217,15 @@
   $ hg cat -r . e
   e
   $ glog --hidden
-  @  4:e8db4aa611f6@bar(stable/draft) touncommit
+  @  4:e8db4aa611f6@bar(/draft) touncommit
   |
-  | x  3:5eb72dbe0cb4@bar(extinct/draft) touncommit
+  | x  3:5eb72dbe0cb4@bar(obsolete/draft) touncommit
   |/
-  o    2:f63b90038565@default(stable/draft) merge
+  o    2:f63b90038565@default(/draft) merge
   |\
-  | o  1:f15c744d48e8@default(stable/draft) addmore
+  | o  1:f15c744d48e8@default(/draft) addmore
   |
-  o  0:07f494440405@default(stable/draft) adda
+  o  0:07f494440405@default(/draft) adda
   
   $ hg bookmarks
    * touncommit-bm             4:e8db4aa611f6
@@ -264,17 +264,17 @@
   R m
   R n
   $ glog --hidden
-  @  5:c706fe2c12f8@bar(stable/draft) touncommit
+  @  5:c706fe2c12f8@bar(/draft) touncommit
   |
-  | o  4:e8db4aa611f6@bar(stable/draft) touncommit
+  | o  4:e8db4aa611f6@bar(/draft) touncommit
   |/
-  | x  3:5eb72dbe0cb4@bar(extinct/draft) touncommit
+  | x  3:5eb72dbe0cb4@bar(obsolete/draft) touncommit
   |/
-  o    2:f63b90038565@default(stable/draft) merge
+  o    2:f63b90038565@default(/draft) merge
   |\
-  | o  1:f15c744d48e8@default(stable/draft) addmore
+  | o  1:f15c744d48e8@default(/draft) addmore
   |
-  o  0:07f494440405@default(stable/draft) adda
+  o  0:07f494440405@default(/draft) adda
   
   $ hg debugobsolete
   5eb72dbe0cb409d094e3b4ae8eaa30071c1b8730 e8db4aa611f6d5706374288e6898e498f5c44098 0 (*) {'user': 'test'} (glob)