branching: merge with stable
authorPierre-Yves David <pierre-yves.david@octobus.net>
Fri, 14 Jul 2017 03:16:06 +0200
changeset 2746 c64e2167514b
parent 2745 b38112b43a27 (diff)
parent 2722 44a6e6fbf80b (current diff)
child 2747 9fd6c8efda5b
branching: merge with stable
tests/test-topic-tutorial.t
--- a/README	Sun Jul 09 15:01:32 2017 +0300
+++ b/README	Fri Jul 14 03:16:06 2017 +0200
@@ -121,6 +121,18 @@
 Changelog
 =========
 
+6.6.0 - in progress
+-------------------
+
+  - amend: add a --extract flag to move change back to the working copy
+    (same as uncommit, but accessible through the amend commit)
+
+  - topic: add --age option to sort topic by the most recently touched,
+  - topic: add a 't0' to access the root of a topic while keeping it active,
+  - topic: allow 'hg prev' to me move to 't0',
+  - topic: add a config option to enforce topic on new commit
+    (experimental.enforce-topic)
+
 6.5.0 -- 2017-07-02
 -------------------
 
--- a/hgext3rd/evolve/__init__.py	Sun Jul 09 15:01:32 2017 +0300
+++ b/hgext3rd/evolve/__init__.py	Fri Jul 14 03:16:06 2017 +0200
@@ -270,7 +270,7 @@
     scmutil,
 )
 
-from mercurial.commands import walkopts, commitopts, commitopts2, mergetoolopts
+from mercurial.commands import commitopts, commitopts2, mergetoolopts
 from mercurial.i18n import _
 from mercurial.node import nullid
 
@@ -278,6 +278,7 @@
     checkheads,
     compat,
     debugcmd,
+    evocommands,
     exthelper,
     metadata,
     obscache,
@@ -313,7 +314,10 @@
 _unpack = struct.unpack
 
 aliases, entry = cmdutil.findcmd('commit', commands.table)
-interactiveopt = [['i', 'interactive', None, _('use interactive mode')]]
+commitopts3 = evocommands.commitopts3
+interactiveopt = evocommands.commitopts3
+_bookmarksupdater = evocommands._bookmarksupdater
+
 # This extension contains the following code
 #
 # - Extension Helper code
@@ -330,6 +334,7 @@
 eh.merge(obshistory.eh)
 eh.merge(templatekw.eh)
 eh.merge(compat.eh)
+eh.merge(evocommands.eh)
 uisetup = eh.final_uisetup
 extsetup = eh.final_extsetup
 reposetup = eh.final_reposetup
@@ -400,25 +405,6 @@
 ### experimental behavior                                         ###
 #####################################################################
 
-commitopts3 = [
-    ('D', 'current-date', None,
-     _('record the current date as commit date')),
-    ('U', 'current-user', None,
-     _('record the current user as committer')),
-]
-
-def _resolveoptions(ui, opts):
-    """modify commit options dict to handle related options
-
-    For now, all it does is figure out the commit date: respect -D unless
-    -d was supplied.
-    """
-    # N.B. this is extremely similar to setupheaderopts() in mq.py
-    if not opts.get('date') and opts.get('current_date'):
-        opts['date'] = '%d %d' % util.makedate()
-    if not opts.get('user') and opts.get('current_user'):
-        opts['user'] = ui.username()
-
 getrevs = obsolete.getrevs
 
 #####################################################################
@@ -974,21 +960,6 @@
     _finalizerelocate(repo, orig, dest, nodenew, tr)
     return nodenew
 
-def _bookmarksupdater(repo, oldid, tr):
-    """Return a callable update(newid) updating the current bookmark
-    and bookmarks bound to oldid to newid.
-    """
-    def updatebookmarks(newid):
-        dirty = False
-        oldbookmarks = repo.nodebookmarks(oldid)
-        if oldbookmarks:
-            for b in oldbookmarks:
-                repo._bookmarks[b] = newid
-            dirty = True
-        if dirty:
-            repo._bookmarks.recordchange(tr)
-    return updatebookmarks
-
 ### new command
 #############################
 metadataopts = [
@@ -1978,7 +1949,7 @@
         with repo.dirstate.parentchange():
             repo.dirstate.setparents(divergent.node(), node.nullid)
         oldlen = len(repo)
-        amend(ui, repo, message='', logfile='')
+        evocommands.amend(ui, repo, message='', logfile='')
         if oldlen == len(repo):
             new = divergent
             # no changes
@@ -2008,6 +1979,69 @@
 
 shorttemplate = "[{label('evolve.rev', rev)}] {desc|firstline}\n"
 
+def _gettopic(ctx):
+    """handle topic fetching with or without the extension"""
+    return getattr(ctx, 'topic', lambda: '')()
+
+def _gettopicidx(ctx):
+    """handle topic fetching with or without the extension"""
+    return getattr(ctx, 'topicidx', lambda: None)()
+
+def _getcurrenttopic(repo):
+    return getattr(repo, 'currenttopic', '')
+
+def _prevupdate(repo, displayer, target, bookmark, dryrun):
+    if dryrun:
+        repo.ui.write(('hg update %s;\n' % target.rev()))
+        if bookmark is not None:
+            repo.ui.write(('hg bookmark %s -r %s;\n'
+                           % (bookmark, target.rev())))
+    else:
+        ret = hg.update(repo, target.rev())
+        if not ret:
+            tr = lock = None
+            try:
+                lock = repo.lock()
+                tr = repo.transaction('previous')
+                if bookmark is not None:
+                    repo._bookmarks[bookmark] = target.node()
+                    repo._bookmarks.recordchange(tr)
+                else:
+                    bookmarksmod.deactivate(repo)
+                tr.close()
+            finally:
+                lockmod.release(tr, lock)
+
+    displayer.show(target)
+
+def _findprevtarget(repo, displayer, movebookmark=False, topic=True):
+    target = bookmark = None
+    wkctx = repo[None]
+    p1 = wkctx.parents()[0]
+    parents = p1.parents()
+    currenttopic = _getcurrenttopic(repo)
+
+    # we do not filter in the 1 case to allow prev to t0
+    if currenttopic and topic and _gettopicidx(p1) != 1:
+        parents = [ctx for ctx in parents if ctx.topic() == currenttopic]
+
+    # issue message for the various case
+    if p1.node() == node.nullid:
+        repo.ui.warn(_('already at repository root\n'))
+    elif not parents and currenttopic:
+        repo.ui.warn(_('no parent in topic "%s"\n') % currenttopic)
+        repo.ui.warn(_('(do you want --no-topic)\n'))
+    elif len(parents) == 1:
+        target = parents[0]
+        bookmark = None
+        if movebookmark:
+            bookmark = repo._activebookmark
+    else:
+        for p in parents:
+            displayer.show(p)
+        repo.ui.warn(_('multiple parents, explicitly update to one\n'))
+    return target, bookmark
+
 @eh.command(
     '^previous',
     [('B', 'move-bookmark', False,
@@ -2037,44 +2071,19 @@
                 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 = repo._activebookmark
-            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:
-                            bookmarksmod.deactivate(repo)
-                        tr.close()
-                    finally:
-                        lockmod.release(tr, lock)
-
-            displayer.show(p)
+        topic = not opts.get("no_topic", False)
+
+        target, bookmark = _findprevtarget(repo, displayer,
+                                           opts.get('move_bookmark'), topic)
+        if target is not None:
+            overrides = {}
+            if topic and _getcurrenttopic(repo) != _gettopic(target):
+                overrides[('_internal', 'keep-topic')] = 'yes'
+            with repo.ui.configoverride(overrides, source='topic-extension'):
+                _prevupdate(repo, displayer, target, bookmark, dryrunopt)
             return 0
         else:
-            for p in parents:
-                displayer.show(p)
-            ui.warn(_('multiple parents, explicitly update to one\n'))
             return 1
     finally:
         lockmod.release(wlock)
@@ -2421,225 +2430,6 @@
     finally:
         lockmod.release(tr, lock, wlock)
 
-@eh.command(
-    'amend|refresh',
-    [('A', 'addremove', None,
-      _('mark new/missing files as added/removed before committing')),
-     ('e', 'edit', False, _('invoke editor on commit messages')),
-     ('', 'close-branch', None,
-      _('mark a branch as closed, hiding it from the branch list')),
-     ('s', 'secret', None, _('use the secret phase for committing')),
-    ] + walkopts + commitopts + commitopts2 + commitopts3 + interactiveopt,
-    _('[OPTION]... [FILE]...'))
-def amend(ui, repo, *pats, **opts):
-    """combine a changeset with updates and replace it with a new one
-
-    Commits a new changeset incorporating both the changes to the given files
-    and all the changes from the current parent changeset into the repository.
-
-    See :hg:`commit` for details about committing changes.
-
-    If you don't specify -m, the parent's message will be reused.
-
-    Behind the scenes, Mercurial first commits the update as a regular child
-    of the current parent. Then it creates a new commit on the parent's parents
-    with the updated contents. Then it changes the working copy parent to this
-    new combined changeset. Finally, the old changeset and its update are hidden
-    from :hg:`log` (unless you use --hidden with log).
-
-    Returns 0 on success, 1 if nothing changed.
-    """
-    opts = opts.copy()
-    edit = opts.pop('edit', False)
-    log = opts.get('logfile')
-    opts['amend'] = True
-    if not (edit or opts['message'] or log):
-        opts['message'] = repo['.'].description()
-    _resolveoptions(ui, opts)
-    _alias, commitcmd = cmdutil.findcmd('commit', commands.table)
-    return commitcmd[0](ui, repo, *pats, **opts)
-
-
-def _touchedbetween(repo, source, dest, match=None):
-    touched = set()
-    for files in repo.status(source, dest, match=match)[:3]:
-        touched.update(files)
-    return touched
-
-def _commitfiltered(repo, ctx, match, target=None):
-    """Recommit ctx with changed files not in match. Return the new
-    node identifier, or None if nothing changed.
-    """
-    base = ctx.p1()
-    if target is None:
-        target = base
-    # ctx
-    initialfiles = _touchedbetween(repo, base, ctx)
-    if base == target:
-        affected = set(f for f in initialfiles if match(f))
-        newcontent = set()
-    else:
-        affected = _touchedbetween(repo, target, ctx, match=match)
-        newcontent = _touchedbetween(repo, target, base, match=match)
-    # The commit touchs all existing files
-    # + all file that needs a new content
-    # - the file affected bny uncommit with the same content than base.
-    files = (initialfiles - affected) | newcontent
-    if not newcontent and files == initialfiles:
-        return None
-
-    # Filter copies
-    copied = copies.pathcopies(target, ctx)
-    copied = dict((dst, src) for dst, src in copied.iteritems()
-                  if dst in files)
-
-    def filectxfn(repo, memctx, path, contentctx=ctx, redirect=newcontent):
-        if path in redirect:
-            return filectxfn(repo, memctx, path, contentctx=target, redirect=())
-        if path not in contentctx:
-            return None
-        fctx = contentctx[path]
-        flags = fctx.flags()
-        mctx = context.memfilectx(repo, fctx.path(), fctx.data(),
-                                  islink='l' in flags,
-                                  isexec='x' in flags,
-                                  copied=copied.get(path))
-        return mctx
-
-    new = context.memctx(repo,
-                         parents=[base.node(), node.nullid],
-                         text=ctx.description(),
-                         files=files,
-                         filectxfn=filectxfn,
-                         user=ctx.user(),
-                         date=ctx.date(),
-                         extra=ctx.extra())
-    # commitctx always create a new revision, no need to check
-    newid = repo.commitctx(new)
-    return newid
-
-def _uncommitdirstate(repo, oldctx, match):
-    """Fix the dirstate after switching the working directory from
-    oldctx to a copy of oldctx not containing changed files matched by
-    match.
-    """
-    ctx = repo['.']
-    ds = repo.dirstate
-    copies = dict(ds.copies())
-    m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
-    for f in m:
-        if ds[f] == 'r':
-            # modified + removed -> removed
-            continue
-        ds.normallookup(f)
-
-    for f in a:
-        if ds[f] == 'r':
-            # added + removed -> unknown
-            ds.drop(f)
-        elif ds[f] != 'a':
-            ds.add(f)
-
-    for f in r:
-        if ds[f] == 'a':
-            # removed + added -> normal
-            ds.normallookup(f)
-        elif ds[f] != 'r':
-            ds.remove(f)
-
-    # Merge old parent and old working dir copies
-    oldcopies = {}
-    for f in (m + a):
-        src = oldctx[f].renamed()
-        if src:
-            oldcopies[f] = src[0]
-    oldcopies.update(copies)
-    copies = dict((dst, oldcopies.get(src, src))
-                  for dst, src in oldcopies.iteritems())
-    # Adjust the dirstate copies
-    for dst, src in copies.iteritems():
-        if (src not in ctx or dst in ctx or ds[dst] != 'a'):
-            src = None
-        ds.copy(src, dst)
-
-@eh.command(
-    '^uncommit',
-    [('a', 'all', None, _('uncommit all changes when no arguments given')),
-     ('r', 'rev', '', _('revert commit content to REV instead')),
-     ] + commands.walkopts,
-    _('[OPTION]... [NAME]'))
-def uncommit(ui, repo, *pats, **opts):
-    """move changes from parent revision to working directory
-
-    Changes to selected files in the checked out revision appear again as
-    uncommitted changed in the working directory. A new revision
-    without the selected changes is created, becomes the checked out
-    revision, and obsoletes the previous one.
-
-    The --include option specifies patterns to uncommit.
-    The --exclude option specifies patterns to keep in the commit.
-
-    The --rev argument let you change the commit file to a content of another
-    revision. It still does not change the content of your file in the working
-    directory.
-
-    Return 0 if changed files are uncommitted.
-    """
-
-    wlock = lock = tr = None
-    try:
-        wlock = repo.wlock()
-        lock = repo.lock()
-        wctx = repo[None]
-        if len(wctx.parents()) <= 0:
-            raise error.Abort(_("cannot uncommit null changeset"))
-        if len(wctx.parents()) > 1:
-            raise error.Abort(_("cannot uncommit while merging"))
-        old = repo['.']
-        if old.phase() == phases.public:
-            raise error.Abort(_("cannot rewrite immutable changeset"))
-        if len(old.parents()) > 1:
-            raise error.Abort(_("cannot uncommit merge changeset"))
-        oldphase = old.phase()
-
-        rev = None
-        if opts.get('rev'):
-            rev = scmutil.revsingle(repo, opts.get('rev'))
-            ctx = repo[None]
-            if ctx.p1() == rev or ctx.p2() == rev:
-                raise error.Abort(_("cannot uncommit to parent changeset"))
-
-        onahead = old.rev() in repo.changelog.headrevs()
-        disallowunstable = not obsolete.isenabled(repo,
-                                                  obsolete.allowunstableopt)
-        if disallowunstable and not onahead:
-            raise error.Abort(_("cannot uncommit in the middle of a stack"))
-
-        # Recommit the filtered changeset
-        tr = repo.transaction('uncommit')
-        updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
-        newid = None
-        includeorexclude = opts.get('include') or opts.get('exclude')
-        if (pats or includeorexclude or opts.get('all')):
-            match = scmutil.match(old, pats, opts)
-            newid = _commitfiltered(repo, old, match, target=rev)
-        if newid is None:
-            raise error.Abort(_('nothing to uncommit'),
-                              hint=_("use --all to uncommit all files"))
-        # Move local changes on filtered changeset
-        obsolete.createmarkers(repo, [(old, (repo[newid],))])
-        phases.retractboundary(repo, tr, oldphase, [newid])
-        with repo.dirstate.parentchange():
-            repo.dirstate.setparents(newid, node.nullid)
-            _uncommitdirstate(repo, old, match)
-        updatebookmarks(newid)
-        if not repo[newid].files():
-            ui.warn(_("new changeset is empty\n"))
-            ui.status(_("(use 'hg prune .' to remove it)\n"))
-        tr.close()
-    finally:
-        lockmod.release(tr, lock, wlock)
-
 @eh.wrapcommand('commit')
 def commitwrapper(orig, ui, repo, *arg, **kwargs):
     tr = None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/evolve/evocommands.py	Fri Jul 14 03:16:06 2017 +0200
@@ -0,0 +1,320 @@
+# Module dedicated to host new commands added by the evolve extensions
+#
+# Copyright 2017 Octobus <contact@octobus.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# Status: Stabilization of the API in progress
+#
+#   The final set of command should go into core.
+#
+#   Some command still live in evolve/__init__.py
+
+from __future__ import absolute_import
+
+from mercurial import (
+    cmdutil,
+    commands,
+    context,
+    copies,
+    error,
+    lock as lockmod,
+    node,
+    obsolete,
+    phases,
+    scmutil,
+    util,
+)
+
+from mercurial.i18n import _
+
+from . import (
+    exthelper,
+)
+
+eh = exthelper.exthelper()
+
+walkopts = commands.walkopts
+commitopts = commands.commitopts
+commitopts2 = commands.commitopts2
+mergetoolopts = commands.mergetoolopts
+
+# option added by evolve
+
+def _resolveoptions(ui, opts):
+    """modify commit options dict to handle related options
+
+    For now, all it does is figure out the commit date: respect -D unless
+    -d was supplied.
+    """
+    # N.B. this is extremely similar to setupheaderopts() in mq.py
+    if not opts.get('date') and opts.get('current_date'):
+        opts['date'] = '%d %d' % util.makedate()
+    if not opts.get('user') and opts.get('current_user'):
+        opts['user'] = ui.username()
+
+commitopts3 = [
+    ('D', 'current-date', None,
+     _('record the current date as commit date')),
+    ('U', 'current-user', None,
+     _('record the current user as committer')),
+]
+
+interactiveopt = [['i', 'interactive', None, _('use interactive mode')]]
+
+def _bookmarksupdater(repo, oldid, tr):
+    """Return a callable update(newid) updating the current bookmark
+    and bookmarks bound to oldid to newid.
+    """
+    def updatebookmarks(newid):
+        dirty = False
+        oldbookmarks = repo.nodebookmarks(oldid)
+        if oldbookmarks:
+            for b in oldbookmarks:
+                repo._bookmarks[b] = newid
+            dirty = True
+        if dirty:
+            repo._bookmarks.recordchange(tr)
+    return updatebookmarks
+
+@eh.command(
+    'amend|refresh',
+    [('A', 'addremove', None,
+      _('mark new/missing files as added/removed before committing')),
+     ('a', 'all', False, _("match all files")),
+     ('e', 'edit', False, _('invoke editor on commit messages')),
+     ('', 'extract', False, _('extract changes from the commit to the working copy')),
+     ('', 'close-branch', None,
+      _('mark a branch as closed, hiding it from the branch list')),
+     ('s', 'secret', None, _('use the secret phase for committing')),
+    ] + walkopts + commitopts + commitopts2 + commitopts3 + interactiveopt,
+    _('[OPTION]... [FILE]...'))
+def amend(ui, repo, *pats, **opts):
+    """combine a changeset with updates and replace it with a new one
+
+    Commits a new changeset incorporating both the changes to the given files
+    and all the changes from the current parent changeset into the repository.
+
+    See :hg:`commit` for details about committing changes.
+
+    If you don't specify -m, the parent's message will be reused.
+
+    If --extra is specified, the behavior of `hg amend` is reversed: Changes
+    to selected files in the checked out revision appear again as uncommitted
+    changed in the working directory.
+
+    Returns 0 on success, 1 if nothing changed.
+    """
+    opts = opts.copy()
+    if opts.get('extract'):
+        if opts.pop('interactive', False):
+            msg = _('not support for --interactive with --extract yet')
+            raise error.Abort(msg)
+        return uncommit(ui, repo, *pats, **opts)
+    else:
+        if opts.pop('all', False):
+            # add an include for all
+            include = list(opts.get('include'))
+            include.append('re:.*')
+        edit = opts.pop('edit', False)
+        log = opts.get('logfile')
+        opts['amend'] = True
+        if not (edit or opts['message'] or log):
+            opts['message'] = repo['.'].description()
+        _resolveoptions(ui, opts)
+        _alias, commitcmd = cmdutil.findcmd('commit', commands.table)
+        return commitcmd[0](ui, repo, *pats, **opts)
+
+def _touchedbetween(repo, source, dest, match=None):
+    touched = set()
+    for files in repo.status(source, dest, match=match)[:3]:
+        touched.update(files)
+    return touched
+
+def _commitfiltered(repo, ctx, match, target=None, message=None, user=None,
+                    date=None):
+    """Recommit ctx with changed files not in match. Return the new
+    node identifier, or None if nothing changed.
+    """
+    base = ctx.p1()
+    if target is None:
+        target = base
+    # ctx
+    initialfiles = _touchedbetween(repo, base, ctx)
+    if base == target:
+        affected = set(f for f in initialfiles if match(f))
+        newcontent = set()
+    else:
+        affected = _touchedbetween(repo, target, ctx, match=match)
+        newcontent = _touchedbetween(repo, target, base, match=match)
+    # The commit touchs all existing files
+    # + all file that needs a new content
+    # - the file affected bny uncommit with the same content than base.
+    files = (initialfiles - affected) | newcontent
+    if not newcontent and files == initialfiles:
+        return None
+
+    # Filter copies
+    copied = copies.pathcopies(target, ctx)
+    copied = dict((dst, src) for dst, src in copied.iteritems()
+                  if dst in files)
+
+    def filectxfn(repo, memctx, path, contentctx=ctx, redirect=newcontent):
+        if path in redirect:
+            return filectxfn(repo, memctx, path, contentctx=target, redirect=())
+        if path not in contentctx:
+            return None
+        fctx = contentctx[path]
+        flags = fctx.flags()
+        mctx = context.memfilectx(repo, fctx.path(), fctx.data(),
+                                  islink='l' in flags,
+                                  isexec='x' in flags,
+                                  copied=copied.get(path))
+        return mctx
+
+    if message is None:
+        message = ctx.description()
+    if not user:
+        user = ctx.user()
+    if not date:
+        date = ctx.date()
+    new = context.memctx(repo,
+                         parents=[base.node(), node.nullid],
+                         text=message,
+                         files=files,
+                         filectxfn=filectxfn,
+                         user=user,
+                         date=date,
+                         extra=ctx.extra())
+    # commitctx always create a new revision, no need to check
+    newid = repo.commitctx(new)
+    return newid
+
+def _uncommitdirstate(repo, oldctx, match):
+    """Fix the dirstate after switching the working directory from
+    oldctx to a copy of oldctx not containing changed files matched by
+    match.
+    """
+    ctx = repo['.']
+    ds = repo.dirstate
+    copies = dict(ds.copies())
+    m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
+    for f in m:
+        if ds[f] == 'r':
+            # modified + removed -> removed
+            continue
+        ds.normallookup(f)
+
+    for f in a:
+        if ds[f] == 'r':
+            # added + removed -> unknown
+            ds.drop(f)
+        elif ds[f] != 'a':
+            ds.add(f)
+
+    for f in r:
+        if ds[f] == 'a':
+            # removed + added -> normal
+            ds.normallookup(f)
+        elif ds[f] != 'r':
+            ds.remove(f)
+
+    # Merge old parent and old working dir copies
+    oldcopies = {}
+    for f in (m + a):
+        src = oldctx[f].renamed()
+        if src:
+            oldcopies[f] = src[0]
+    oldcopies.update(copies)
+    copies = dict((dst, oldcopies.get(src, src))
+                  for dst, src in oldcopies.iteritems())
+    # Adjust the dirstate copies
+    for dst, src in copies.iteritems():
+        if (src not in ctx or dst in ctx or ds[dst] != 'a'):
+            src = None
+        ds.copy(src, dst)
+
+@eh.command(
+    '^uncommit',
+    [('a', 'all', None, _('uncommit all changes when no arguments given')),
+     ('r', 'rev', '', _('revert commit content to REV instead')),
+     ] + commands.walkopts + commitopts + commitopts2 + commitopts3,
+    _('[OPTION]... [NAME]'))
+def uncommit(ui, repo, *pats, **opts):
+    """move changes from parent revision to working directory
+
+    Changes to selected files in the checked out revision appear again as
+    uncommitted changed in the working directory. A new revision
+    without the selected changes is created, becomes the checked out
+    revision, and obsoletes the previous one.
+
+    The --include option specifies patterns to uncommit.
+    The --exclude option specifies patterns to keep in the commit.
+
+    The --rev argument let you change the commit file to a content of another
+    revision. It still does not change the content of your file in the working
+    directory.
+
+    Return 0 if changed files are uncommitted.
+    """
+
+    _resolveoptions(ui, opts) # process commitopts3
+    wlock = lock = tr = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+        wctx = repo[None]
+        if len(wctx.parents()) <= 0:
+            raise error.Abort(_("cannot uncommit null changeset"))
+        if len(wctx.parents()) > 1:
+            raise error.Abort(_("cannot uncommit while merging"))
+        old = repo['.']
+        if old.phase() == phases.public:
+            raise error.Abort(_("cannot rewrite immutable changeset"))
+        if len(old.parents()) > 1:
+            raise error.Abort(_("cannot uncommit merge changeset"))
+        oldphase = old.phase()
+
+        rev = None
+        if opts.get('rev'):
+            rev = scmutil.revsingle(repo, opts.get('rev'))
+            ctx = repo[None]
+            if ctx.p1() == rev or ctx.p2() == rev:
+                raise error.Abort(_("cannot uncommit to parent changeset"))
+
+        onahead = old.rev() in repo.changelog.headrevs()
+        disallowunstable = not obsolete.isenabled(repo,
+                                                  obsolete.allowunstableopt)
+        if disallowunstable and not onahead:
+            raise error.Abort(_("cannot uncommit in the middle of a stack"))
+
+        # Recommit the filtered changeset
+        tr = repo.transaction('uncommit')
+        updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
+        newid = None
+        includeorexclude = opts.get('include') or opts.get('exclude')
+        if (pats or includeorexclude or opts.get('all')):
+            match = scmutil.match(old, pats, opts)
+            if not (opts['message'] or opts['logfile']):
+                opts['message'] = old.description()
+            message = cmdutil.logmessage(ui, opts)
+            newid = _commitfiltered(repo, old, match, target=rev,
+                                    message=message, user=opts.get('user'),
+                                    date=opts.get('date'))
+        if newid is None:
+            raise error.Abort(_('nothing to uncommit'),
+                              hint=_("use --all to uncommit all files"))
+        # Move local changes on filtered changeset
+        obsolete.createmarkers(repo, [(old, (repo[newid],))])
+        phases.retractboundary(repo, tr, oldphase, [newid])
+        with repo.dirstate.parentchange():
+            repo.dirstate.setparents(newid, node.nullid)
+            _uncommitdirstate(repo, old, match)
+        updatebookmarks(newid)
+        if not repo[newid].files():
+            ui.warn(_("new changeset is empty\n"))
+            ui.status(_("(use 'hg prune .' to remove it)\n"))
+        tr.close()
+    finally:
+        lockmod.release(tr, lock, wlock)
--- a/hgext3rd/evolve/metadata.py	Sun Jul 09 15:01:32 2017 +0300
+++ b/hgext3rd/evolve/metadata.py	Fri Jul 14 03:16:06 2017 +0200
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-__version__ = '6.5.1.dev'
+__version__ = '6.6.0.dev'
 testedwith = '3.8.4 3.9.2 4.0.2 4.1.3 4.2.1'
 minimumhgversion = '3.8'
 buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/topic/__init__.py	Sun Jul 09 15:01:32 2017 +0300
+++ b/hgext3rd/topic/__init__.py	Fri Jul 14 03:16:06 2017 +0200
@@ -53,6 +53,7 @@
 from __future__ import absolute_import
 
 import re
+import time
 
 from mercurial.i18n import _
 from mercurial import (
@@ -68,9 +69,11 @@
     namespaces,
     node,
     obsolete,
+    obsutil,
     patch,
     phases,
     registrar,
+    templatefilters,
     util,
 )
 
@@ -113,7 +116,7 @@
               'topic.active': 'green',
              }
 
-version = '0.1.1.dev'
+version = '0.2.0.dev'
 testedwith = '4.0.2 4.1.3 4.2.1'
 minimumhgversion = '4.0'
 buglink = 'https://bz.mercurial-scm.org/'
@@ -123,6 +126,19 @@
         return ''
     return self.extra().get(constants.extrakey, '')
 context.basectx.topic = _contexttopic
+def _contexttopicidx(self):
+    topic = self.topic()
+    if not topic:
+        # XXX we might want to include t0 here,
+        # however t0 is related to  'currenttopic' which has no place here.
+        return None
+    revlist = stack.getstack(self._repo, topic=topic)
+    try:
+        return revlist.index(self.rev())
+    except IndexError:
+        # Lets move to the last ctx of the current topic
+        return None
+context.basectx.topicidx = _contexttopicidx
 
 topicrev = re.compile(r'^t\d+$')
 branchrev = re.compile(r'^b\d+$')
@@ -144,10 +160,14 @@
 
     if revs is not None:
         try:
-            r = revs[idx - 1]
+            r = revs[idx]
         except IndexError:
             msg = _('cannot resolve "%s": %s "%s" has only %d changesets')
-            raise error.Abort(msg % (name, ttype, tname, len(revs)))
+            raise error.Abort(msg % (name, ttype, tname, len(revs) - 1))
+        # b0 or t0 can be None
+        if r == -1 and idx == 0:
+            msg = _('the %s "%s" has no %s')
+            raise error.Abort(msg % (ttype, tname, name))
         return [repo[r].node()]
     if name not in repo.topics:
         return []
@@ -176,6 +196,11 @@
 
     extensions.wrapfunction(cmdutil, 'buildcommittext', committextwrap)
     extensions.wrapfunction(merge, 'update', mergeupdatewrap)
+    # We need to check whether t0 or b0 is passed to override the default update
+    # behaviour of changing topic and I can't find a better way
+    # to do that as scmutil.revsingle returns the rev number and hence we can't
+    # plug into logic for this into mergemod.update().
+    extensions.wrapcommand(commands.table, 'update', checkt0)
 
     try:
         evolve = extensions.find('evolve')
@@ -283,9 +308,30 @@
         ('', 'clear', False, 'clear active topic if any'),
         ('r', 'rev', '', 'revset of existing revisions', _('REV')),
         ('l', 'list', False, 'show the stack of changeset in the topic'),
+        ('', 'age', False, 'show when you last touched the topics')
     ] + commands.formatteropts)
 def topics(ui, repo, topic='', clear=False, rev=None, list=False, **opts):
-    """View current topic, set current topic, or see all topics.
+    """View current topic, set current topic, change topic for a set of revisions, or see all topics.
+
+    Clear topic on existing topiced revisions:
+        `hg topic --rev <related revset> --clear`
+
+    Change topic on some revisions:
+        `hg topic <newtopicname> --rev <related revset>`
+
+    Clear current topic:
+        `hg topic --clear`
+
+    Set current topic:
+        `hg topic <topicname>`
+
+    List of topics:
+        `hg topics`
+
+    List of topics with their last touched time sorted according to it:
+        `hg topic --age`
+
+    The active topic (if any) will be prepended with a "*".
 
     The --verbose version of this command display various information on the state of each topic."""
     if list:
@@ -411,6 +457,11 @@
 
 def _listtopics(ui, repo, opts):
     fm = ui.formatter('topics', opts)
+    showlast = opts.get('age')
+    if showlast:
+        # we have a new function as plugging logic into existing function is
+        # pretty much difficult
+        return _showlasttouched(repo, fm, opts)
     activetopic = repo.currenttopic
     namemask = '%s'
     if repo.topics and ui.verbose:
@@ -463,6 +514,76 @@
         fm.plain('\n')
     fm.end()
 
+def _showlasttouched(repo, fm, opts):
+    topics = repo.topics
+    timedict = _getlasttouched(repo, topics)
+    times = timedict.keys()
+    times.sort()
+    if topics:
+        maxwidth = max(len(t) for t in topics)
+        namemask = '%%-%is' % maxwidth
+    activetopic = repo.currenttopic
+    for timevalue in times:
+        curtopics = timedict[timevalue][1]
+        for topic in curtopics:
+            fm.startitem()
+            marker = ' '
+            label = 'topic'
+            active = (topic == activetopic)
+            if active:
+                marker = '*'
+                label = 'topic.active'
+            fm.plain(' %s ' % marker, label=label)
+            fm.write('topic', namemask, topic, label=label)
+            fm.data(active=active)
+            fm.plain(' (')
+            if timevalue == -1:
+                timestr = 'not yet touched'
+            else:
+                timestr = templatefilters.age(timedict[timevalue][0])
+            fm.write('lasttouched', '%s', timestr, label='topic.list.time')
+            fm.plain(')')
+            fm.plain('\n')
+    fm.end()
+
+def _getlasttouched(repo, topics):
+    """
+    Calculates the last time a topic was used. Returns a dictionary of seconds
+    passed from current time for a topic as keys and topic name as values.
+    """
+    topicstime = {}
+    curtime = time.time()
+    for t in topics:
+        maxtime = (0, 0)
+        trevs = repo.revs("topic(%s)", t)
+        # Need to check for the time of all changesets in the topic, whether
+        # they are obsolete of non-heads
+        # XXX: can we just rely on the max rev number for this
+        for revs in trevs:
+            rt = repo[revs].date()
+            if rt[0] > maxtime[0]:
+                # Can store the rev to gather more info
+                # latesthead = revs
+                maxtime = rt
+            # looking on the markers also to get more information and accurate
+            # last touch time.
+            obsmarkers = obsutil.getmarkers(repo, [repo[revs].node()])
+            for marker in obsmarkers:
+                rt = marker.date()
+                if rt[0] > maxtime[0]:
+                    maxtime = rt
+        # is the topic still yet untouched
+        if not trevs:
+            secspassed = -1
+        else:
+            secspassed = (curtime - maxtime[0])
+        try:
+            topicstime[secspassed][1].append(t)
+        except KeyError:
+            topicstime[secspassed] = (maxtime, [t])
+
+    return topicstime
+
 def summaryhook(ui, repo):
     t = repo.currenttopic
     if not t:
@@ -472,10 +593,16 @@
 
 def commitwrap(orig, ui, repo, *args, **opts):
     with repo.wlock():
+        enforcetopic = ui.configbool('experimental', 'enforce-topic')
         if opts.get('topic'):
             t = opts['topic']
             with repo.vfs.open('topic', 'w') as f:
                 f.write(t)
+        elif not repo.currenttopic and enforcetopic:
+            msg = _("no active topic")
+            hint = _("set a current topic or use '--config " +
+                     "experimental.enforce-topic=no' to commit without a topic")
+            raise error.Abort(msg, hint=hint)
         return orig(ui, repo, *args, **opts)
 
 def committextwrap(orig, repo, ctx, subs, extramsg):
@@ -491,6 +618,7 @@
     partial = not (matcher is None or matcher.always())
     wlock = repo.wlock()
     isrebase = False
+    ist0 = False
     try:
         ret = orig(repo, node, branchmerge, force, *args, **kwargs)
         # The mergeupdatewrap function makes the destination's topic as the
@@ -500,7 +628,9 @@
         # running.
         if repo.ui.hasconfig('experimental', 'topicrebase'):
             isrebase = True
-        if (not partial and not branchmerge) or isrebase:
+        if repo.ui.configbool('_internal', 'keep-topic'):
+            ist0 = True
+        if ((not partial and not branchmerge) or isrebase) and not ist0:
             ot = repo.currenttopic
             t = ''
             pctx = repo[node]
@@ -510,10 +640,23 @@
                 f.write(t)
             if t and t != ot:
                 repo.ui.status(_("switching to topic %s\n") % t)
+        elif ist0:
+            repo.ui.status(_("preserving the current topic '%s'\n") %
+                           repo.currenttopic)
         return ret
     finally:
         wlock.release()
 
+def checkt0(orig, ui, repo, node=None, rev=None, clean=False, date=None,
+            check=False, merge=None, tool=None):
+
+    thezeros = set(['t0', 'b0'])
+    overrides = {}
+    if node in thezeros or rev in thezeros:
+        overrides[('_internal', 'keep-topic')] = 'yes'
+    with repo.ui.configoverride(overrides, source='topic-extension'):
+        return orig(ui, repo, node, rev, clean, date, check, merge, tool)
+
 def _fixrebase(loaded):
     if not loaded:
         return
--- a/hgext3rd/topic/revset.py	Sun Jul 09 15:01:32 2017 +0300
+++ b/hgext3rd/topic/revset.py	Fri Jul 14 03:16:06 2017 +0200
@@ -78,7 +78,7 @@
         topic = repo.currenttopic
     if not topic:
         branch = repo[None].branch()
-    return revset.baseset(stack.getstack(repo, branch=branch, topic=topic)) & subset
+    return revset.baseset(stack.getstack(repo, branch=branch, topic=topic)[1:]) & subset
 
 
 def modsetup(ui):
--- a/hgext3rd/topic/stack.py	Sun Jul 09 15:01:32 2017 +0300
+++ b/hgext3rd/topic/stack.py	Fri Jul 14 03:16:06 2017 +0200
@@ -20,7 +20,13 @@
         trevs = repo.revs("branch(%s) - public() - obsolete() - topic()", branch)
     else:
         raise error.ProgrammingError('neither branch and topic specified (not defined yet)')
-    return _orderrevs(repo, trevs)
+    revs = _orderrevs(repo, trevs)
+    if revs:
+        pt1 = repo[revs[0]].p1()
+        if pt1.obsolete():
+            pt1 = repo[_singlesuccessor(repo, pt1)]
+        revs.insert(0, pt1.rev())
+    return revs
 
 def labelsgen(prefix, labelssuffix):
     """ Takes a label prefix and a list of suffixes. Returns a string of the prefix
@@ -84,8 +90,16 @@
             fm.plain('%d behind' % data['behindcount'], label='topic.stack.summary.behindcount')
     fm.plain('\n')
 
-    for idx, r in enumerate(getstack(repo, branch=branch, topic=topic), 1):
+    for idx, r in enumerate(getstack(repo, branch=branch, topic=topic), 0):
         ctx = repo[r]
+        # special case for t0, b0 as it's hard to plugin into rest of the logic
+        if idx == 0:
+            # t0, b0 can be None
+            if r == -1:
+                continue
+            entries.append((idx, False, ctx))
+            prev = ctx.rev()
+            continue
         p1 = ctx.p1()
         if p1.obsolete():
             p1 = repo[_singlesuccessor(repo, p1)]
@@ -148,7 +162,7 @@
     :behindcount: number of changeset on rebase destination
     """
     data = {}
-    revs = getstack(repo, branch, topic)
+    revs = getstack(repo, branch, topic)[1:]
     data['changesetcount'] = len(revs)
     data['troubledcount'] = len([r for r in revs if repo[r].troubled()])
     deps, rdeps = builddependencies(repo, revs)
--- a/tests/test-amend.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-amend.t	Fri Jul 14 03:16:06 2017 +0200
@@ -132,11 +132,9 @@
   
       If you don't specify -m, the parent's message will be reused.
   
-      Behind the scenes, Mercurial first commits the update as a regular child
-      of the current parent. Then it creates a new commit on the parent's
-      parents with the updated contents. Then it changes the working copy parent
-      to this new combined changeset. Finally, the old changeset and its update
-      are hidden from 'hg log' (unless you use --hidden with log).
+      If --extra is specified, the behavior of 'hg amend' is reversed: Changes
+      to selected files in the checked out revision appear again as uncommitted
+      changed in the working directory.
   
       Returns 0 on success, 1 if nothing changed.
   
@@ -144,7 +142,9 @@
   
    -A --addremove           mark new/missing files as added/removed before
                             committing
+   -a --all                 match all files
    -e --edit                invoke editor on commit messages
+      --extract             extract changes from the commit to the working copy
       --close-branch        mark a branch as closed, hiding it from the branch
                             list
    -s --secret              use the secret phase for committing
--- a/tests/test-discovery-obshashrange.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-discovery-obshashrange.t	Fri Jul 14 03:16:06 2017 +0200
@@ -34,23 +34,9 @@
   * @0000000000000000000000000000000000000000 (*)> serve --stdio (glob)
   * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio exited 0 after *.?? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> debugbuilddag .+7 (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (8r, 0o) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (8r, 0o) (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (8r, 0o) (glob)
   * @0000000000000000000000000000000000000000 (*)> debugbuilddag .+7 exited 0 after *.?? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
@@ -166,10 +152,10 @@
   $ rm ../server/.hg/blackbox.log
   $ hg blackbox
   * @0000000000000000000000000000000000000000 (*)> pull --rev 4 (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
   * @0000000000000000000000000000000000000000 (*)> updated stablerange cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (5r, 3o) (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated base branch cache in *.???? seconds (glob)
+  * @0000000000000000000000000000000000000000 (*)> wrote base branch cache with 1 labels and 1 nodes (glob)
   * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (5r, 3o) (glob)
   * @0000000000000000000000000000000000000000 (*)> 5 incoming changes - new heads: bebd167eb94d (glob)
   * @0000000000000000000000000000000000000000 (*)> pull --rev 4 exited 0 after *.?? seconds (glob)
@@ -206,7 +192,7 @@
   taking quick initial sample
   query 2; still undecided: 5, sample size is: 5
   sending known command
-  2 total queries
+  2 total queries in *.????s (glob)
   preparing listkeys for "phases"
   sending listkeys command
   received listkey for "phases": 58 bytes
@@ -238,7 +224,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   remote: 1 new obsolescence markers
-  bundle2-input-bundle: with-transaction
+  bundle2-input-bundle: no-transaction
   bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
   bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
   bundle2-input-part: "reply:obsmarkers" (params: 0 advisory) supported
@@ -248,12 +234,12 @@
   received listkey for "phases": 58 bytes
   $ hg -R ../server blackbox
   * @0000000000000000000000000000000000000000 (*)> serve --stdio (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated stablerange cache in *.???? seconds (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
+  * @0000000000000000000000000000000000000000 (*)> obscache is out of date, falling back to slower obsstore version (glob)
   * @0000000000000000000000000000000000000000 (*)> updated served branch cache in *.???? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated stablerange cache in *.???? seconds (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
-  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob)
+  * @0000000000000000000000000000000000000000 (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob)
   * @0000000000000000000000000000000000000000 (*)> 1 incoming changes - new heads: 45f8b879de92 (glob)
   * @0000000000000000000000000000000000000000 (*)> -R server serve --stdio exited 0 after *.?? seconds (glob)
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
@@ -310,10 +296,11 @@
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> add foo (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> add foo exited 0 after *.?? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> commit -m foo (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated served branch cache in *.???? seconds (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 0o) (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obscache is out of date, falling back to slower obsstore version (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 1 nodes (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> commit -m foo exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob)
@@ -322,6 +309,7 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push -f --debug (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> found 1 common and 1 unknown server heads, 2 roundtrips in *.????s (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/5 mismatch - 1 obshashrange queries in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push -f --debug exited 0 after *.?? seconds (glob)
@@ -342,7 +330,7 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete 22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 2/6 mismatch - 1 obshashrange queries in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push exited True after *.?? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> push exited 1 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
   $ rm .hg/blackbox.log
   $ hg debugobsolete | sort
@@ -421,13 +409,12 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> log -G exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull -r 6 (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 2/6 mismatch - 1 obshashrange queries in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (2r, 0o) (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obshashcache reset - new markers affect cached ranges (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (2r, 3o) (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 3o) (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (2r, 3o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 2 incoming changes - new heads: f69452c5b1af (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull -r 6 exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
@@ -567,17 +554,18 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobshashrange --subranges --rev 'heads(all())' exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated served branch cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 1 incoming changes - new heads: 4de32a90b66c (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> rollback (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated base branch cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-obscache cache reset (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (8r, 12o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> rollback exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
   $ rm .hg/blackbox.log
@@ -617,11 +605,9 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobshashrange --subranges --rev 'heads(all())' exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> obsdiscovery, 0/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip detected, evo-ext-obscache cache reset (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (9r, 12o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated stablerange cache in *.???? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 1o) (glob)
-  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (0r, 1o) (glob)
+  * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> updated evo-ext-obscache in *.???? seconds (1r, 1o) (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> 1 incoming changes - new heads: 4de32a90b66c (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> pull exited 0 after *.?? seconds (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
@@ -695,10 +681,12 @@
   pulling from ssh://user@dummy/server
   searching for changes
   OBSEXC: looking for common markers in 8 nodes
+  OBSEXC: request obsmarkers for 1 common nodes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+  2 new obsolescence markers
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg log -G
   o  8 45f8b879de92 foo tip
@@ -728,9 +716,9 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> strip -r 'desc("foo")' (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> saved backup bundle to $TESTTMP/client/.hg/strip-backup/45f8b879de92-94c82517-backup.hg (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-obshashrange cache reset (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (5r, 13o) (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (5r, 11o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> strip detected, evo-ext-obscache cache reset (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (5r, 13o) (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (5r, 11o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated stablerange cache in *.???? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (3r, 0o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (3r, 0o) (glob)
@@ -742,12 +730,13 @@
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> writing .hg/cache/tags2-visible with 0 tags (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> log -G exited 0 after *.?? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> pull (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> obsdiscovery, 0/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (1r, 0o) (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> obsdiscovery, 1/8 mismatch - 1 obshashrange queries in *.???? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated stablerange cache in *.???? seconds (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 0o) (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated served branch cache in *.???? seconds (glob)
-  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> obshashcache reset - new markers affect cached ranges (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obshashrange in *.???? seconds (1r, 2o) (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated base branch cache in *.???? seconds (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
+  * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> updated evo-ext-obscache in *.???? seconds (1r, 2o) (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> 1 incoming changes - new heads: 45f8b879de92 (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> pull exited 0 after *.?? seconds (glob)
   * @bebd167eb94d257ace0e814aeb98e6972ed2970d (*)> log -G (glob)
--- a/tests/test-drop.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-drop.t	Fri Jul 14 03:16:06 2017 +0200
@@ -207,11 +207,13 @@
   | x  changeset:   3:87ea30a976fd
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    pruned
   | |  summary:     temporary amend commit for 34b6c051bf1f
   | |
   | x  changeset:   2:34b6c051bf1f
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as a2c06c884bfe
   |    summary:     add child
   |
   o  changeset:   1:19509a42b0d0
@@ -263,4 +265,3 @@
      summary:     add base
   
   ============ obsmark ============
-  87ea30a976fdf235bf096f04899cb02a903873e2 0 {34b6c051bf1f78db6aef400776de5cb964470207} (*) {'ef1': '0', 'user': 'test'} (glob)
--- a/tests/test-evolve-cycles.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-cycles.t	Fri Jul 14 03:16:06 2017 +0200
@@ -62,16 +62,19 @@
   |  tag:         tip
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as 2a34000d3544
   |  summary:     C
   |
   x  changeset:   2:c473644ee0e9
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as a8df460dbbfe
   |  summary:     B
   |
   @  changeset:   1:2a34000d3544
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as c473644ee0e9
   |  summary:     A
   |
   o  changeset:   0:ea207398892e
@@ -204,31 +207,37 @@
   |  tag:         tip
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as 868d2e0eb19c
   |  summary:     F
   |
   x  changeset:   5:0da815c333f6
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as d9f908fde1a1
   |  summary:     E
   |
   @  changeset:   4:868d2e0eb19c
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as 0da815c333f6
   |  summary:     D
   |
   x  changeset:   3:a8df460dbbfe
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    split as 2a34000d3544, 868d2e0eb19c
   |  summary:     C
   |
   x  changeset:   2:c473644ee0e9
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as a8df460dbbfe
   |  summary:     B
   |
   x  changeset:   1:2a34000d3544
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    rewritten as c473644ee0e9
   |  summary:     A
   |
   o  changeset:   0:ea207398892e
--- a/tests/test-evolve-obshistory-complex.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-obshistory-complex.t	Fri Jul 14 03:16:06 2017 +0200
@@ -99,21 +99,25 @@
   x | |  changeset:   4:868d2e0eb19c
   | | |  user:        test
   | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  obsolete:    rewritten as d15d0ffc75f6
   | | |  summary:     D
   | | |
   x | |  changeset:   3:a8df460dbbfe
   |/ /   user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    rewritten as d15d0ffc75f6
   | |    summary:     C
   | |
   x |  changeset:   2:c473644ee0e9
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    rewritten as b868bc49b0a4
   | |  summary:     B
   | |
   x |  changeset:   1:2a34000d3544
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as b868bc49b0a4
   |    summary:     A
   |
   o  changeset:   0:ea207398892e
@@ -269,21 +273,25 @@
   x | |  changeset:   4:868d2e0eb19c
   | | |  user:        test
   | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  obsolete:    split as 7b3290f6e0a0, d0f33db50670
   | | |  summary:     D
   | | |
   x | |  changeset:   3:a8df460dbbfe
   |/ /   user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    split as 7b3290f6e0a0, d0f33db50670
   | |    summary:     C
   | |
   x |  changeset:   2:c473644ee0e9
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    split as 19e14c8397fc, e036916b63ea
   | |  summary:     B
   | |
   x |  changeset:   1:2a34000d3544
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    split as 19e14c8397fc, e036916b63ea
   |    summary:     A
   |
   o  changeset:   0:ea207398892e
@@ -330,21 +338,25 @@
   x | |  changeset:   4:868d2e0eb19c
   | | |  user:        test
   | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  obsolete:    split as 7b3290f6e0a0, ec31316faa9d
   | | |  summary:     D
   | | |
   x | |  changeset:   3:a8df460dbbfe
   |/ /   user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    split as 7b3290f6e0a0, ec31316faa9d
   | |    summary:     C
   | |
   x |  changeset:   2:c473644ee0e9
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    split as 19e14c8397fc, 7b3290f6e0a0
   | |  summary:     B
   | |
   x |  changeset:   1:2a34000d3544
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    split as 19e14c8397fc, 7b3290f6e0a0
   |    summary:     A
   |
   o  changeset:   0:ea207398892e
--- a/tests/test-evolve-obshistory.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-obshistory.t	Fri Jul 14 03:16:06 2017 +0200
@@ -41,11 +41,13 @@
   | x  changeset:   2:f137d23bb3e1
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    pruned
   | |  summary:     temporary amend commit for 471f378eab4c
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as 4ae3a4151de9
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -59,7 +61,7 @@
   @  4ae3a4151de9 (3) A1
   |
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as 4ae3a4151de9 (glob)
+       rewritten(description, content) by test (Thu Jan 01 00:00:00 1970 +0000) as 4ae3a4151de9
          --- a/471f378eab4c-changeset-description
          +++ b/4ae3a4151de9-changeset-description
          @@ -1,1 +1,3 @@
@@ -197,6 +199,7 @@
   |  tag:         tip
   |  user:        test
   |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  obsolete:    pruned
   |  summary:     B0
   |
   @  changeset:   1:471f378eab4c
@@ -336,6 +339,7 @@
   | x  changeset:   1:471597cad322
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    split as 337fec4d2edc, f257fde29c7a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -589,6 +593,7 @@
   | x  changeset:   1:de7290d8b885
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    split as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -764,11 +769,13 @@
   | x  changeset:   2:0dec01379d3b
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    rewritten as eb5a0daa2192
   | |  summary:     B0
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as eb5a0daa2192
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -969,6 +976,7 @@
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1001,6 +1009,8 @@
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
+  |    obsolete:    rewritten as 65b757b745b9
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1282,6 +1292,7 @@
   | x  changeset:   2:0dec01379d3b
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as b7ea6d14e664
   |    summary:     B0
   |
   o  changeset:   1:471f378eab4c
@@ -1309,16 +1320,19 @@
   | |  parent:      1:471f378eab4c
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    rewritten as eb5a0daa2192
   | |  summary:     B1
   | |
   | | x  changeset:   2:0dec01379d3b
   | |/   user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    rewritten as b7ea6d14e664
   | |    summary:     B0
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as eb5a0daa2192
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1542,11 +1556,13 @@
   |/   parent:      0:ea207398892e
   |    user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as 7a230b46bf61
   |    summary:     A1
   |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1587,6 +1603,7 @@
   adding file changes
   added 1 changesets with 0 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads, 'hg merge' to merge)
   working directory parent is obsolete! (471f378eab4c)
   (use 'hg evolve' to update to its successor: 7a230b46bf61)
--- a/tests/test-evolve-serveronly-bundle2.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-serveronly-bundle2.t	Fri Jul 14 03:16:06 2017 +0200
@@ -108,6 +108,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   remote: 2 new obsolescence markers
+  remote: obsoleted 1 changesets
   $ cat ../errors.log
   $ hg push
   pushing to http://localhost:$HGPORT/
@@ -127,6 +128,7 @@
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
   2 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads)
   $ cat ../errors.log
   $ hg -R ../other pull
--- a/tests/test-evolve-templates.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-templates.t	Fri Jul 14 03:16:06 2017 +0200
@@ -47,16 +47,19 @@
   |/   parent:      0:ea207398892e
   |    user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten by test2 as d004c8f274b9
   |    summary:     A1
   |
   | x  changeset:   2:f137d23bb3e1
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    pruned by test1
   | |  summary:     temporary amend commit for 471f378eab4c
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten by test1 as a468dc9b3633
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -76,10 +79,10 @@
   o  d004c8f274b9 (4) A2
   |
   x  a468dc9b3633 (3) A1
-  |    rewritten(description) by test2 (*) as d004c8f274b9 (glob)
+  |    rewritten(description) by test2 (Thu Apr 19 04:25:21 2001 +0000) as d004c8f274b9
   |
   @  471f378eab4c (1) A0
-       rewritten(description, content) by test1 (*) as a468dc9b3633 (glob)
+       rewritten(description, content) by test1 (Fri Feb 13 23:31:30 2009 +0000) as a468dc9b3633
   
   $ hg tlog
   o  d004c8f274b9
@@ -113,7 +116,7 @@
   o  d004c8f274b9
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten by test1, test2 as d004c8f274b9 (between * and *) (glob)
+  |/     Obsfate: rewritten by test1, test2 as d004c8f274b9 (between 2001-04-19 04:25 +0000 and 2009-02-13 23:31 +0000)
   |
   o  ea207398892e
   
@@ -180,7 +183,7 @@
   o  d004c8f274b9
   |
   | @  a468dc9b3633
-  |/     Obsfate: rewritten by test2 as d004c8f274b9 (at *) (glob)
+  |/     Obsfate: rewritten by test2 as d004c8f274b9 (at 2001-04-19 04:25 +0000)
   |
   o  ea207398892e
   
@@ -222,13 +225,13 @@
   @  d004c8f274b9
   |
   | x  a468dc9b3633
-  |/     Obsfate: rewritten by test2 as d004c8f274b9 (at *) (glob)
+  |/     Obsfate: rewritten by test2 as d004c8f274b9 (at 2001-04-19 04:25 +0000)
   |
   | x  f137d23bb3e1
-  | |    Obsfate: pruned by test1 (at *) (glob)
+  | |    Obsfate: pruned by test1 (at 2009-02-13 23:31 +0000)
   | |
   | x  471f378eab4c
-  |/     Obsfate: rewritten by test1 as a468dc9b3633 (at *) (glob)
+  |/     Obsfate: rewritten by test1 as a468dc9b3633 (at 2009-02-13 23:31 +0000)
   |
   o  ea207398892e
   
@@ -236,11 +239,11 @@
   $ hg fatelogjson --hidden
   @  d004c8f274b9 ""
   |
-  | x  a468dc9b3633 [{"markers": [["a468dc9b36338b14fdb7825f55ce3df4e71517ad", ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], 0, [["ef1", "1"], ["user", "test2"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], "users": ["test2"], "verb": "rewritten"}] (glob)
+  | x  a468dc9b3633 [{"markers": [["a468dc9b36338b14fdb7825f55ce3df4e71517ad", ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], 0, [["ef1", "1"], ["user", "test2"]], [987654321.0, 0], null]], "max_date": [987654321.0, 0], "min_date": [987654321.0, 0], "successors": ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], "users": ["test2"], "verb": "rewritten"}]
   |/
-  | x  f137d23bb3e1 [{"markers": [["f137d23bb3e11dc1daeb6264fac9cb2433782e15", [], 0, [["ef1", "0"], ["user", "test1"]], [*, 0], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]], "max_date": [*, 0], "min_date": [*, 0], "successors": [], "users": ["test1"], "verb": "pruned"}] (glob)
+  | x  f137d23bb3e1 [{"markers": [["f137d23bb3e11dc1daeb6264fac9cb2433782e15", [], 0, [["ef1", "0"], ["user", "test1"]], [1234567890.0, 0], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]], "max_date": [1234567890.0, 0], "min_date": [1234567890.0, 0], "successors": [], "users": ["test1"], "verb": "pruned"}]
   | |
-  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], 0, [["ef1", "9"], ["user", "test1"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], "users": ["test1"], "verb": "rewritten"}] (glob)
+  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], 0, [["ef1", "9"], ["user", "test1"]], [1234567890.0, 0], null]], "max_date": [1234567890.0, 0], "min_date": [1234567890.0, 0], "successors": ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], "users": ["test1"], "verb": "rewritten"}]
   |/
   o  ea207398892e ""
   
@@ -319,6 +322,7 @@
   | x  changeset:   1:471597cad322
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    split as 337fec4d2edc, f257fde29c7a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -405,7 +409,7 @@
   |
   o  337fec4d2edc ""
   |
-  | x  471597cad322 [{"markers": [["471597cad322d1f659bb169751be9133dad92ef3", ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], 0, [["ef1", "12"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], "users": ["test"], "verb": "split"}] (glob)
+  | x  471597cad322 [{"markers": [["471597cad322d1f659bb169751be9133dad92ef3", ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], 0, [["ef1", "12"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], "users": ["test"], "verb": "split"}]
   |/
   o  ea207398892e ""
   
@@ -452,11 +456,13 @@
   | x  changeset:   2:0dec01379d3b
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    rewritten as eb5a0daa2192
   | |  summary:     B0
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as eb5a0daa2192
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -570,9 +576,9 @@
   $ hg fatelogjson --hidden
   @  eb5a0daa2192 ""
   |
-  | x  0dec01379d3b [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "13"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  0dec01379d3b [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "13"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}]
   | |
-  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "9"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "9"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}]
   |/
   o  ea207398892e ""
   
@@ -599,6 +605,7 @@
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -631,6 +638,8 @@
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
+  |    obsolete:    rewritten as 65b757b745b9
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -734,11 +743,11 @@
   $ hg fatelogjson --hidden
   o  019fadeab383 ""
   |
-  | x  65b757b745b9 [{"markers": [["65b757b745b935093c87a2bccd877521cccffcbd", ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  65b757b745b9 [{"markers": [["65b757b745b935093c87a2bccd877521cccffcbd", ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], "users": ["test"], "verb": "rewritten"}]
   |/
   | @  fdf9bde5129a ""
   |/
-  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], "users": ["test"], "verb": "rewritten"}, {"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["65b757b745b935093c87a2bccd877521cccffcbd"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["65b757b745b935093c87a2bccd877521cccffcbd"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], "users": ["test"], "verb": "rewritten"}, {"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["65b757b745b935093c87a2bccd877521cccffcbd"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["65b757b745b935093c87a2bccd877521cccffcbd"], "users": ["test"], "verb": "rewritten"}]
   |/
   o  ea207398892e ""
   
@@ -766,6 +775,7 @@
   | x  changeset:   2:0dec01379d3b
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as b7ea6d14e664
   |    summary:     B0
   |
   o  changeset:   1:471f378eab4c
@@ -793,16 +803,19 @@
   | |  parent:      1:471f378eab4c
   | |  user:        test
   | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  obsolete:    rewritten as eb5a0daa2192
   | |  summary:     B1
   | |
   | | x  changeset:   2:0dec01379d3b
   | |/   user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    rewritten as b7ea6d14e664
   | |    summary:     B0
   | |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as eb5a0daa2192
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -947,11 +960,11 @@
   $ hg fatelogjson --hidden
   @  eb5a0daa2192 ""
   |
-  | x  b7ea6d14e664 [{"markers": [["b7ea6d14e664bdc8922221f7992631b50da3fb07", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "13"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  b7ea6d14e664 [{"markers": [["b7ea6d14e664bdc8922221f7992631b50da3fb07", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "13"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}]
   | |
-  | | x  0dec01379d3b [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | | x  0dec01379d3b [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], "users": ["test"], "verb": "rewritten"}]
   | |/
-  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "9"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["ef1", "9"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], "users": ["test"], "verb": "rewritten"}]
   |/
   o  ea207398892e ""
   
@@ -997,11 +1010,13 @@
   |/   parent:      0:ea207398892e
   |    user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as 7a230b46bf61
   |    summary:     A1
   |
   | x  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as fdf9bde5129a
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1018,6 +1033,7 @@
   adding file changes
   added 1 changesets with 0 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads, 'hg merge' to merge)
   working directory parent is obsolete! (471f378eab4c)
   (use 'hg evolve' to update to its successor: 7a230b46bf61)
@@ -1032,6 +1048,7 @@
   | @  changeset:   1:471f378eab4c
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as 7a230b46bf61
   |    summary:     A0
   |
   o  changeset:   0:ea207398892e
@@ -1057,7 +1074,7 @@
   o  7a230b46bf61
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten by test as 7a230b46bf61 (between * and *) (glob)
+  |/     Obsfate: rewritten by test as 7a230b46bf61 (at 1970-01-01 00:00 +0000)
   |
   o  ea207398892e
   
@@ -1088,7 +1105,7 @@
   @  7a230b46bf61
   |
   | x  471f378eab4c
-  |/     Obsfate: rewritten by test as 7a230b46bf61 (between * and *) (glob)
+  |/     Obsfate: rewritten by test as 7a230b46bf61 (at 1970-01-01 00:00 +0000)
   |
   o  ea207398892e
   
@@ -1096,7 +1113,7 @@
   $ hg fatelogjson --hidden
   @  7a230b46bf61 ""
   |
-  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null], ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e", ["7a230b46bf61e50b30308c6cfd7bd1269ef54702"], 0, [["ef1", "1"], ["user", "test"]], [*, 0], null]], "max_date": [*, 0], "min_date": [*, 0], "successors": ["7a230b46bf61e50b30308c6cfd7bd1269ef54702"], "users": ["test"], "verb": "rewritten"}] (glob)
+  | x  471f378eab4c [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null], ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e", ["7a230b46bf61e50b30308c6cfd7bd1269ef54702"], 0, [["ef1", "1"], ["user", "test"]], [0.0, 0], null]], "max_date": [0.0, 0], "min_date": [0.0, 0], "successors": ["7a230b46bf61e50b30308c6cfd7bd1269ef54702"], "users": ["test"], "verb": "rewritten"}]
   |/
   o  ea207398892e ""
   
@@ -1131,7 +1148,7 @@
   
   $ hg fatelog -v
   @  471f378eab4c
-  |    Obsfate: pruned by test (at *) (glob)
+  |    Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
   |
   o  ea207398892e
   
--- a/tests/test-evolve-topic.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-evolve-topic.t	Fri Jul 14 03:16:06 2017 +0200
@@ -78,7 +78,7 @@
   t3: add eee
   t2: add ddd
   t1: add ccc
-    ^ add bbb
+  t0^ add bbb (base)
   $ hg up 'desc(ddd)'
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ echo ddd >> ddd
@@ -209,9 +209,14 @@
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   [16] add ggg
   $ hg prev
+  preserving the current topic 'bar'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  [15] add fff
+  $ hg prev
   no parent in topic "bar"
   (do you want --no-topic)
+  [1]
   $ hg prev --no-topic
   switching to topic foo
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  [15] add fff
+  [14] add eee
--- a/tests/test-exchange-obsmarkers-case-A3.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-exchange-obsmarkers-case-A3.t	Fri Jul 14 03:16:06 2017 +0200
@@ -242,6 +242,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   remote: 1 new obsolescence markers
+  remote: obsoleted 1 changesets
   ## post push state
   # obstore: main
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -257,6 +258,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads, 'hg merge' to merge)
   1 new unstable changesets
   ## post pull state
--- a/tests/test-exchange-obsmarkers-case-A6.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-exchange-obsmarkers-case-A6.t	Fri Jul 14 03:16:06 2017 +0200
@@ -108,6 +108,7 @@
   searching for changes
   no changes found
   remote: 1 new obsolescence markers
+  remote: obsoleted 1 changesets
   ## post push state
   # obstore: main
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -118,6 +119,7 @@
   pulling from main
   no changes found
   1 new obsolescence markers
+  obsoleted 1 changesets
   ## post pull state
   # obstore: main
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -141,6 +143,7 @@
   searching for changes
   no changes found
   remote: 1 new obsolescence markers
+  remote: obsoleted 1 changesets
   ## post push state
   # obstore: main
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -152,6 +155,7 @@
   searching for changes
   no changes found
   1 new obsolescence markers
+  obsoleted 1 changesets
   ## post pull state
   # obstore: main
   28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
--- a/tests/test-inhibit.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-inhibit.t	Fri Jul 14 03:16:06 2017 +0200
@@ -686,6 +686,8 @@
   adding manifests
   adding file changes
   added 2 changesets with 1 changes to 2 files (+1 heads)
+  3 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads .' to see heads, 'hg merge' to merge)
 
  Only allow direct access and check that evolve works like before
--- a/tests/test-obsolete.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-obsolete.t	Fri Jul 14 03:16:06 2017 +0200
@@ -126,6 +126,7 @@
   parent:      1:7c3bad9141dc
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
+  obsolete:    rewritten as 725c380fe99b
   summary:     add obsol_c
   
   working directory parent is obsolete! (0d3f46688ccc)
@@ -237,6 +238,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
   $ qlog -R ../other-new
   5
   - 95de7fc6918d
@@ -274,6 +276,7 @@
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
   1 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ qlog -R ../other-new
   6
@@ -364,6 +367,7 @@
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
   1 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads, 'hg merge' to merge)
 
   $ hg up -q 7 # to check rollback update behavior
@@ -455,6 +459,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
+  updated to "159dfc9fa5d3: add obsol_d''"
   1 other heads for branch "default"
   $ hg id -n
   8
@@ -539,6 +544,7 @@
   adding file changes
   added 2 changesets with 1 changes to [12] files (re)
   3 new obsolescence markers
+  obsoleted 1 changesets
   $ hg up -q 10
   $ mkcommit "obsol_d'''"
   created new head
@@ -551,6 +557,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
   $ cd ..
 
 check bumped detection
@@ -739,12 +746,14 @@
   | | | x  changeset:   14:33d458d86621
   | | | |  user:        test
   | | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | | |  obsolete:    pruned
   | | | |  summary:     temporary amend commit for 0b1b6dd009c0
   | | | |
   | | | x  changeset:   13:0b1b6dd009c0
   | | |/   parent:      10:2033b4e49474
   | | |    user:        test
   | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    obsolete:    rewritten as 705ab2a6b72e
   | | |    summary:     add f
   | | |
   | | | o  changeset:   12:6db5e282cb91
@@ -769,30 +778,36 @@
   | |    parent:      -1:000000000000
   | |    user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    pruned
   | |    summary:     add toto
   | |
   | | x  changeset:   8:159dfc9fa5d3
   | | |  parent:      3:0d3f46688ccc
   | | |  user:        test
   | | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |  obsolete:    rewritten as 9468a5f5d8b2
   | | |  summary:     add obsol_d''
   | | |
   | | | x  changeset:   7:909a0fb57e5d
   | | |/   parent:      3:0d3f46688ccc
   | | |    user:        test
   | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    obsolete:    rewritten as 159dfc9fa5d3
   | | |    summary:     add obsol_d'
   | | |
   | | | x  changeset:   6:95de7fc6918d
   | | |/   parent:      3:0d3f46688ccc
   | | |    user:        test
   | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    obsolete:    rewritten as 909a0fb57e5d
   | | |    summary:     add obsol_d
   | | |
   | | | x  changeset:   5:a7a6f2b5d8a5
   | | |/   parent:      3:0d3f46688ccc
   | | |    user:        test
   | | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | | |    obsolete:    rewritten as 95de7fc6918d
+  | | |    obsolete:    rewritten as 50f11e5e3a63
   | | |    summary:     add d
   | | |
   | o |  changeset:   4:725c380fe99b
@@ -805,11 +820,14 @@
   | |/   parent:      1:7c3bad9141dc
   | |    user:        test
   | |    date:        Thu Jan 01 00:00:00 1970 +0000
+  | |    obsolete:    rewritten as 725c380fe99b
+  | |    obsolete:    rewritten as 2033b4e49474
   | |    summary:     add obsol_c
   | |
   x |  changeset:   2:4538525df7e2
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as 0d3f46688ccc
   |    summary:     add c
   |
   o  changeset:   1:7c3bad9141dc
--- a/tests/test-prev-next.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-prev-next.t	Fri Jul 14 03:16:06 2017 +0200
@@ -5,7 +5,8 @@
   $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
 
 hg prev -B should move active bookmark
-  $ hg init
+  $ hg init test-repo
+  $ cd test-repo
   $ touch a
   $ hg add a
   $ hg commit -m 'added a'
@@ -93,6 +94,15 @@
      mark                      2:4e26ef31f919
      no-move                   2:4e26ef31f919
 
+test prev on root
+
+  $ hg up null
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ hg prev
+  already at repository root
+  [1]
+  $ hg up 1
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 Behavior with local modification
 --------------------------------
@@ -216,6 +226,8 @@
   atop:[6] added b (3)
   working directory is now at 47ea25be8aea
 
+  $ cd ..
+
 prev and next should lock properly against other commands
 
   $ hg init repo
--- a/tests/test-push-checkheads-pruned-B1.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B1.t	Fri Jul 14 03:16:06 2017 +0200
@@ -68,5 +68,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B2.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B2.t	Fri Jul 14 03:16:06 2017 +0200
@@ -81,5 +81,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B3.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B3.t	Fri Jul 14 03:16:06 2017 +0200
@@ -81,6 +81,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
 
--- a/tests/test-push-checkheads-pruned-B4.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B4.t	Fri Jul 14 03:16:06 2017 +0200
@@ -82,5 +82,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B5.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B5.t	Fri Jul 14 03:16:06 2017 +0200
@@ -88,5 +88,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   3 new obsolescence markers
+  obsoleted 3 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B6.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B6.t	Fri Jul 14 03:16:06 2017 +0200
@@ -74,5 +74,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B7.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B7.t	Fri Jul 14 03:16:06 2017 +0200
@@ -73,5 +73,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-pruned-B8.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-pruned-B8.t	Fri Jul 14 03:16:06 2017 +0200
@@ -94,5 +94,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   4 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A1.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A1.t	Fri Jul 14 03:16:06 2017 +0200
@@ -65,5 +65,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A2.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A2.t	Fri Jul 14 03:16:06 2017 +0200
@@ -83,5 +83,6 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A3.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A3.t	Fri Jul 14 03:16:06 2017 +0200
@@ -86,5 +86,6 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A4.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A4.t	Fri Jul 14 03:16:06 2017 +0200
@@ -70,5 +70,6 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../../
--- a/tests/test-push-checkheads-superceed-A5.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A5.t	Fri Jul 14 03:16:06 2017 +0200
@@ -70,6 +70,7 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
 
--- a/tests/test-push-checkheads-superceed-A6.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A6.t	Fri Jul 14 03:16:06 2017 +0200
@@ -94,5 +94,6 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A7.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A7.t	Fri Jul 14 03:16:06 2017 +0200
@@ -94,5 +94,6 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 2 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-superceed-A8.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-superceed-A8.t	Fri Jul 14 03:16:06 2017 +0200
@@ -75,5 +75,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-unpushed-D4.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-unpushed-D4.t	Fri Jul 14 03:16:06 2017 +0200
@@ -118,5 +118,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-unpushed-D5.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-unpushed-D5.t	Fri Jul 14 03:16:06 2017 +0200
@@ -103,5 +103,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files
   1 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-push-checkheads-unpushed-D7.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-push-checkheads-unpushed-D7.t	Fri Jul 14 03:16:06 2017 +0200
@@ -92,5 +92,6 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   3 new obsolescence markers
+  obsoleted 1 changesets
 
   $ cd ../..
--- a/tests/test-sharing.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-sharing.t	Fri Jul 14 03:16:06 2017 +0200
@@ -88,7 +88,9 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  updated to "60ffde5765c5: fix bug 37"
   1 other heads for branch "default"
 
 Figure SG03
@@ -120,6 +122,7 @@
   $ cd ../test-repo
   $ hg update
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  updated to "de6151c48e1c: fix bug 37"
   1 other heads for branch "default"
   $ hg shortlog --hidden -G
   @  4:de6151c48e1c  draft  fix bug 37
@@ -209,6 +212,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   updating bookmark bug15
   $ hg -R ../review bookmarks
      bug15                     3:cbdfbd5a5db2
@@ -253,6 +257,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   updating bookmark featureX
 
 Bob receives second review, amends, and pushes to public:
@@ -278,6 +283,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   2 new obsolescence markers
+  obsoleted 1 changesets
   updating bookmark featureX
   $ hg -R ../review bookmarks
      bug15                     3:cbdfbd5a5db2
@@ -393,6 +399,7 @@
   adding file changes
   added 1 changesets with 0 changes to 1 files
   1 new obsolescence markers
+  obsoleted 1 changesets
   updating bookmark bug15
 
 Figure SG08: review and public changesets after Alice pushes.
--- a/tests/test-stabilize-conflict.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-stabilize-conflict.t	Fri Jul 14 03:16:06 2017 +0200
@@ -152,6 +152,7 @@
   |/   parent:      0:29ec1554cfaf
   |    user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as e04690b09bc6
   |    summary:     babar count up to ten
   |
   o  changeset:   0:29ec1554cfaf
@@ -243,6 +244,7 @@
   |/   parent:      0:29ec1554cfaf
   |    user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as b20d08eea373
   |    summary:     babar count up to ten
   |
   o  changeset:   0:29ec1554cfaf
--- a/tests/test-stabilize-order.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-stabilize-order.t	Fri Jul 14 03:16:06 2017 +0200
@@ -221,6 +221,7 @@
   | x  changeset:   12:2256dae6521f
   |/   user:        test
   |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    obsolete:    rewritten as f83a0bce03e4
   |    summary:     addc
   |
   o  changeset:   11:7a68bc4596ea
--- a/tests/test-stack-branch.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-stack-branch.t	Fri Jul 14 03:16:06 2017 +0200
@@ -75,7 +75,7 @@
   b3: c_e
   b2: c_d
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
 
 Test "t#" reference
 -------------------
@@ -123,7 +123,7 @@
   b3$ c_e (unstable)
   b2@ c_d (current)
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
   $ hg up b3
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg stack
@@ -132,7 +132,7 @@
   b3$ c_e (current unstable)
   b2: c_d
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
   $ hg up b2
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 
@@ -206,7 +206,7 @@
   b3: c_g
   b2: c_d
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
 
 Case with multiple heads on the topic with unstability involved
 ---------------------------------------------------------------
@@ -249,7 +249,7 @@
   b3: c_g
   b2@ c_D (current)
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
 
 Check that stack doesn't show draft changesets on a branch
 ----------------------------------------------------------
@@ -263,7 +263,7 @@
   b3: c_g
   b2@ c_D (current)
   b1: c_c
-    ^ c_b
+  b0^ c_b (base)
   $ hg phase --public b1
   $ hg stack
   ### branch: foo (2 heads)
@@ -273,7 +273,7 @@
   b3: c_h
   b2: c_g
   b1@ c_D (current)
-    ^ c_c
+  b0^ c_c (base)
 
 Check that stack doesn't show changeset with a topic
 ----------------------------------------------------
@@ -285,4 +285,4 @@
   b3: c_h
   b2: c_g
   b1@ c_D (current)
-    ^ c_c
+  b0^ c_c (base)
--- a/tests/test-topic-fold.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic-fold.t	Fri Jul 14 03:16:06 2017 +0200
@@ -54,7 +54,7 @@
   ### topic: myfeature
   ### branch: default
   t1@ folded (current)
-    ^ add ROOT
+  t0^ add ROOT (base)
   $ logtopic
   @  3:4fd43e5bdc443dc8489edffac19bd8f93ccf1a5c
   |  topics: myfeature
--- a/tests/test-topic-rebase.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic-rebase.t	Fri Jul 14 03:16:06 2017 +0200
@@ -46,7 +46,7 @@
   ### topic: myfeature
   ### branch: default
   t1@ add feature1 (current)
-    ^ add ROOT
+  t0^ add ROOT (base)
   $ logtopic
   @  1:39e7a938055e87615edf675c24a10997ff05bb06
   |  topics: myfeature
@@ -76,7 +76,7 @@
   ### topic: myfeature
   ### branch: default
   t1@ add feature1 (current)
-    ^ add default
+  t0^ add default (base)
   $ logtopic
   @  3:fc6593661cf3256ba165cbccd6019ead17cc3726
   |  topics: myfeature
@@ -90,7 +90,7 @@
   ### topic: myfeature
   ### branch: default
   t1@ add feature1 (current)
-    ^ add default
+  t0^ add default (base)
 
 Check that rebase keep the topic in case of merge conflict
 ----------------------------------------------------------
@@ -152,11 +152,11 @@
   ### topic: myotherfeature
   ### branch: default
   t1@ myotherfeature1 (current)
-    ^ default3
+  t0^ default3 (base)
   $ hg update --rev 7
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg stack
   ### topic: myotherfeature
   ### branch: default
   t1@ myotherfeature1 (current)
-    ^ default3
+  t0^ default3 (base)
--- a/tests/test-topic-stack-data.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic-stack-data.t	Fri Jul 14 03:16:06 2017 +0200
@@ -248,23 +248,23 @@
   t3: bar1_d
   t2: add bar_b
   t1: add bar_a
-    ^ add base_e
+  t0^ add base_e (base)
   $ hg stack baz
   ### topic: baz
   ### branch: default, 2 behind
   t2: add baz_b
   t1: add baz_a
-    ^ add base_c
+  t0^ add base_c (base)
   $ hg stack foo
   ### topic: foo
   ### branch: lake, ambigious rebase destination
   t2@ add foo_b (current)
   t1: add foo_a
-    ^ add lake_a
+  t0^ add lake_a (base)
   $ hg stack fuz
   ### topic: fuz
   ### branch: default, 1 behind
   t3$ add fuz_c (unstable)
   t2$ add fuz_b (unstable)
   t1: fuz1_a
-    ^ add base_d
+  t0^ add base_d (base)
--- a/tests/test-topic-stack.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic-stack.t	Fri Jul 14 03:16:06 2017 +0200
@@ -76,7 +76,7 @@
   t3: c_e
   t2: c_d
   t1: c_c
-    ^ c_b
+  t0^ c_b (base)
   $ hg stack -Tjson | python -m json.tool
   [
       {
@@ -118,6 +118,7 @@
       {
           "isentry": false,
           "topic.stack.desc": "c_b",
+          "topic.stack.index": 0,
           "topic.stack.state": [
               "base"
           ],
@@ -180,7 +181,7 @@
   t3$ c_e (unstable)
   t2@ c_d (current)
   t1: c_c
-    ^ c_b
+  t0^ c_b (base)
   $ hg up t3
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg topic --list
@@ -190,7 +191,7 @@
   t3$ c_e (current unstable)
   t2: c_d
   t1: c_c
-    ^ c_b
+  t0^ c_b (base)
   $ hg topic --list --color=debug
   [topic.stack.summary.topic|### topic: [topic.active|foo]]
   [topic.stack.summary.branches|### branch: default]
@@ -198,7 +199,7 @@
   [topic.stack.index topic.stack.index.current topic.stack.index.unstable|t3][topic.stack.state topic.stack.state.current topic.stack.state.unstable|$] [topic.stack.desc topic.stack.desc.current topic.stack.desc.unstable|c_e][topic.stack.state topic.stack.state.current topic.stack.state.unstable| (current unstable)]
   [topic.stack.index topic.stack.index.clean|t2][topic.stack.state topic.stack.state.clean|:] [topic.stack.desc topic.stack.desc.clean|c_d]
   [topic.stack.index topic.stack.index.clean|t1][topic.stack.state topic.stack.state.clean|:] [topic.stack.desc topic.stack.desc.clean|c_c]
-    [topic.stack.state topic.stack.state.base|^] [topic.stack.desc topic.stack.desc.base|c_b]
+  [topic.stack.index topic.stack.index.base|t0][topic.stack.state topic.stack.state.base|^] [topic.stack.desc topic.stack.desc.base|c_b][topic.stack.state topic.stack.state.base| (base)]
   $ hg up t2
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 
@@ -281,7 +282,7 @@
   t3: c_g
   t2: c_d
   t1: c_c
-    ^ c_b
+  t0^ c_b (base)
 
 Case with multiple heads on the topic with unstability involved
 ---------------------------------------------------------------
@@ -325,7 +326,7 @@
   t3: c_g
   t2@ c_D (current)
   t1: c_c
-    ^ c_b
+  t0^ c_b (base)
 
 Trying to list non existing topic
   $ hg stack thisdoesnotexist
--- a/tests/test-topic-tutorial.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic-tutorial.t	Fri Jul 14 03:16:06 2017 +0200
@@ -126,7 +126,7 @@
   ### branch: default
   t2@ adding fruits (current)
   t1: adding condiments
-    ^ Shopping list
+  t0^ Shopping list (base)
 
 The topic deactivates when we update away from it::
 
@@ -361,7 +361,7 @@
   ### branch: default
   t2@ Adding orange juice (current)
   t1: Adding apple juice
-    ^ adding fruits
+  t0^ adding fruits (base)
   $ hg up tools
   switching to topic tools
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -371,7 +371,7 @@
   t3@ Adding drill (current)
   t2: Adding saw
   t1: Adding hammer
-    ^ adding fruits
+  t0^ adding fruits (base)
 
 They are seen as independent branches by Mercurial. No rebase or merge
 between them will be attempted by default::
@@ -479,5 +479,5 @@
   t3@ Adding drill (current)
   t2: Adding saw
   t1: Adding hammer
-    ^ add a pair of shoes
+  t0^ add a pair of shoes (base)
 
--- a/tests/test-topic.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-topic.t	Fri Jul 14 03:16:06 2017 +0200
@@ -15,7 +15,28 @@
   $ hg help topics
   hg topics [TOPIC]
   
-  View current topic, set current topic, or see all topics.
+  View current topic, set current topic, change topic for a set of revisions, or
+  see all topics.
+  
+      Clear topic on existing topiced revisions:
+          'hg topic --rev <related revset> --clear'
+  
+      Change topic on some revisions:
+          'hg topic <newtopicname> --rev <related revset>'
+  
+      Clear current topic:
+          'hg topic --clear'
+  
+      Set current topic:
+          'hg topic <topicname>'
+  
+      List of topics:
+          'hg topics'
+  
+      List of topics with their last touched time sorted according to it:
+          'hg topic --age'
+  
+      The active topic (if any) will be prepended with a "*".
   
       The --verbose version of this command display various information on the
       state of each topic.
@@ -25,6 +46,7 @@
       --clear   clear active topic if any
    -r --rev REV revset of existing revisions
    -l --list    show the stack of changeset in the topic
+      --age     show when you last touched the topics
   
   (some details hidden, use --verbose to show complete help)
   $ hg topics
@@ -777,3 +799,69 @@
   |  date:        Thu Jan 01 00:00:00 1970 +0000
   |  summary:     start on fran
   |
+
+Testing for updating to t0
+==========================
+
+  $ hg stack
+  ### topic: changewut (2 heads)
+  ### branch: default, 5 behind
+  t3: fran?
+  t1^ start on fran (base)
+  t2@ gamma (current)
+  t1: start on fran
+  t0^ Add file delta (base)
+  $ hg up t0
+  preserving the current topic 'changewut'
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg topic
+   * changewut
+  $ hg stack
+  ### topic: changewut (2 heads)
+  ### branch: default, 5 behind
+  t3: fran?
+  t1^ start on fran (base)
+  t2: gamma
+  t1: start on fran
+  t0^ Add file delta (base)
+
+  $ hg topics --age
+   * changewut (1970-01-01)
+
+  $ cd ..
+
+Testing the new config knob to forbid untopiced commit
+======================================================
+
+  $ hg init ponky
+  $ cd ponky
+  $ cat <<EOF >> .hg/hgrc
+  > [phases]
+  > publish=false
+  > EOF
+  $ cat <<EOF >> $HGRCPATH
+  > [experimental]
+  > enforce-topic = yes
+  > EOF
+  $ touch a b c d
+  $ hg add a
+  $ hg ci -m "Added a"
+  abort: no active topic
+  (set a current topic or use '--config experimental.enforce-topic=no' to commit without a topic)
+  [255]
+
+(same test, checking we abort before the editor)
+
+  $ EDITOR=cat hg ci -m "Added a" --edit
+  abort: no active topic
+  (set a current topic or use '--config experimental.enforce-topic=no' to commit without a topic)
+  [255]
+  $ hg ci -m "added a" --config experimental.enforce-topic=no
+  $ hg log
+  changeset:   0:a154386e50d1
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     added a
+  
+  $ cd ..
--- a/tests/test-tutorial.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-tutorial.t	Fri Jul 14 03:16:06 2017 +0200
@@ -461,6 +461,12 @@
    -r --rev VALUE           revert commit content to REV instead
    -I --include PATTERN [+] include names matching the given patterns
    -X --exclude PATTERN [+] exclude names matching the given patterns
+   -m --message TEXT        use text as commit message
+   -l --logfile FILE        read commit message from file
+   -d --date DATE           record the specified date as commit date
+   -u --user USER           record the specified user as committer
+   -D --current-date        record the current date as commit date
+   -U --current-user        record the current user as committer
   
   (some details hidden, use --verbose to show complete help)
 
@@ -733,6 +739,7 @@
   adding file changes
   added 2 changesets with 2 changes to 1 files (+1 heads)
   3 new obsolescence markers
+  obsoleted 2 changesets
 
 remote get a warning that current working directory is based on an obsolete changeset
 
--- a/tests/test-uncommit.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-uncommit.t	Fri Jul 14 03:16:06 2017 +0200
@@ -358,7 +358,103 @@
 
 Test uncommiting precursors
 
-  $ hg uncommit --hidden --rev 'precursors(.)' b
+  $ hg uncommit --hidden --rev 'precursors(.)' b --traceback
   $ hg cat b --rev .
   b
   b
+
+Test date, message and user update
+
+  $ hg log -r .
+  changeset:   12:912ed871207c
+  branch:      bar
+  tag:         tip
+  parent:      7:4f1c269eab68
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     touncommit
+  
+  $ hg uncommit -m 'to-uncommit' d --user test2 --date '1337 0'
+  $ hg log -r .
+  changeset:   13:f1efd9ec508c
+  branch:      bar
+  tag:         tip
+  parent:      7:4f1c269eab68
+  user:        test2
+  date:        Thu Jan 01 00:22:17 1970 +0000
+  summary:     to-uncommit
+  
+
+test -U option
+
+  $ hg uncommit -U b
+  $ hg log -r .
+  changeset:   14:288da4a95941
+  branch:      bar
+  tag:         tip
+  parent:      7:4f1c269eab68
+  user:        test
+  date:        Thu Jan 01 00:22:17 1970 +0000
+  summary:     to-uncommit
+  
+
+test the `hg amend --extract` entry point
+
+  $ hg status --change .
+  M j
+  M o
+  A e
+  A ff
+  A h
+  A k
+  A l
+  R c
+  R f
+  R g
+  R m
+  R n
+  $ hg status
+  M d
+  A aa
+  R b
+  $ hg amend --extract j
+  $ hg status --change .
+  M o
+  A e
+  A ff
+  A h
+  A k
+  A l
+  R c
+  R f
+  R g
+  R m
+  R n
+  $ hg status
+  M d
+  M j
+  A aa
+  R b
+
+(with all)
+
+  $ hg amend --extract --all
+  new changeset is empty
+  (use 'hg prune .' to remove it)
+  $ hg status --change .
+  $ hg status
+  M d
+  M j
+  M o
+  A aa
+  A e
+  A ff
+  A h
+  A k
+  A l
+  R b
+  R c
+  R f
+  R g
+  R m
+  R n
--- a/tests/test-userguide.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-userguide.t	Fri Jul 14 03:16:06 2017 +0200
@@ -18,7 +18,7 @@
 example 2: unsafe amend with plain vanilla Mercurial: the original
 commit is stripped
   $ hg commit --amend -u alice -d '1 0' -m 'implement feature Y'
-  saved backup bundle to $TESTTMP/t/.hg/strip-backup/6e725fd2be6f-42cc74d4-amend-backup.hg (glob)
+  saved backup bundle to $TESTTMP/t/.hg/strip-backup/6e725fd2be6f-42cc74d4-amend.hg (glob)
   $ hg log -r 23fe4ac6d3f1
   abort: unknown revision '23fe4ac6d3f1'!
   [255]
--- a/tests/test-wireproto-bundle1.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-wireproto-bundle1.t	Fri Jul 14 03:16:06 2017 +0200
@@ -70,6 +70,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   remote: 2 new obsolescence markers
+  remote: obsoleted 1 changesets
   $ hg push
   pushing to ssh://user@dummy/server
   searching for changes
@@ -87,6 +88,7 @@
   adding file changes
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
   2 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads)
   $ hg -R ../other pull
   pulling from ssh://user@dummy/server
--- a/tests/test-wireproto.t	Sun Jul 09 15:01:32 2017 +0300
+++ b/tests/test-wireproto.t	Fri Jul 14 03:16:06 2017 +0200
@@ -74,6 +74,7 @@
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   remote: obsmarker-exchange: 151 bytes received
   remote: 2 new obsolescence markers
+  remote: obsoleted 1 changesets
   $ hg push
   pushing to ssh://user@dummy/server
   searching for changes
@@ -92,6 +93,7 @@
   added 1 changesets with 1 changes to [12] files \(\+1 heads\) (re)
   obsmarker-exchange: 151 bytes received
   2 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads)
   $ hg -R ../other pull
   pulling from ssh://user@dummy/server
@@ -136,8 +138,9 @@
   remote: adding manifests
   remote: adding file changes
   remote: added 1 changesets with 0 changes to 1 files (+1 heads)
-  remote: obsmarker-exchange: 227 bytes received
+  remote: obsmarker-exchange: 226 bytes received
   remote: 1 new obsolescence markers
+  remote: obsoleted 1 changesets
   $ hg -R ../other pull
   pulling from ssh://user@dummy/server
   searching for changes
@@ -145,8 +148,9 @@
   adding manifests
   adding file changes
   added 1 changesets with 0 changes to 1 files (+1 heads)
-  obsmarker-exchange: 227 bytes received
+  obsmarker-exchange: 226 bytes received
   1 new obsolescence markers
+  obsoleted 1 changesets
   (run 'hg heads' to see heads)
 
 test discovery avoid exchanging known markers
@@ -169,7 +173,7 @@
   (skipping discovery of obsolescence markers, will exchange everything)
   (controled by 'experimental.evolution.obsdiscovery' configuration)
   no changes found
-  remote: obsmarker-exchange: 377 bytes received
+  remote: obsmarker-exchange: 376 bytes received
   [1]
   $ hg -R ../other pull --config experimental.evolution.obsdiscovery=no
   pulling from ssh://user@dummy/server
@@ -177,6 +181,6 @@
   no changes found
   (skipping discovery of obsolescence markers, will exchange everything)
   (controled by 'experimental.evolution.obsdiscovery' configuration)
-  obsmarker-exchange: 377 bytes received
+  obsmarker-exchange: 376 bytes received
 
   $ cd ..