compat-test: merge future 6.7.0 into 4.1 compat branch mercurial-4.1
authorPierre-Yves David <pierre-yves.david@octobus.net>
Wed, 27 Sep 2017 01:12:47 +0200
branchmercurial-4.1
changeset 3002 00e4d31b8cdb
parent 2809 f25c79365f5d (current diff)
parent 3001 67b59d1657cf (diff)
child 3003 ddf28837f5af
child 3109 3024ae293732
compat-test: merge future 6.7.0 into 4.1 compat branch (mergeing through 4.2 compat branch)
tests/test-discovery-obshashrange.t
tests/test-evolve-obshistory.t
tests/test-evolve-serveronly-bundle2.t
tests/test-evolve-templates.t
tests/test-evolve.t
tests/test-inhibit.t
tests/test-obsolete.t
tests/test-prev-next.t
tests/test-prune.t
tests/test-topic-stack.t
tests/test-topic-tutorial.t
tests/test-userguide.t
tests/test-wireproto-bundle1.t
tests/test-wireproto.t
--- a/.hgtags	Tue Jul 25 15:17:42 2017 +0200
+++ b/.hgtags	Wed Sep 27 01:12:47 2017 +0200
@@ -55,3 +55,4 @@
 e358c0263e4629746a7c925429c951f67d4b02b1 6.3.1
 e60248f26f923f4460682252f7863ff86f7b86b0 6.4.0
 734c0bc066cdc0121a20a9cb44c8cc30c653be94 6.5.0
+cc3e09e033a3c632c9ac35badbf8b5d53f584049 6.6.0
--- a/README	Tue Jul 25 15:17:42 2017 +0200
+++ b/README	Wed Sep 27 01:12:47 2017 +0200
@@ -121,6 +121,26 @@
 Changelog
 =========
 
+6.7.0 - in progress
+-------------------
+
+  * documentation: improvement to content, wording and graphs,
+  * compatibility with change in future 4.4 at this release date,
+  * obslog/log: improve verb used to describe and evolution,
+  * obslog: improved templatability
+  * pstatus/pdiff: update to full command. They now appears in the help.
+  * uncommit: add a --interactive option.
+
+  * stack: improve display of interleaved topic
+  * stack: improve display of merge commit
+  * topic: gain a --current flag
+  * topic: add a new 'debugconvertbookmark' commands.
+    It helps migrating from bookmark feature branch to topic feature branch.
+  * topic: small clarification and cleanup on various output
+  * push: add a --topic option to mirror --bookmark and --branch.
+  * topic: be more informative about topic activation and deactivation
+  * topic: --age flag also shows the user who last touched the topic
+
 6.6.0 -- 2017-07-25
 -------------------
 
--- a/debian/changelog	Tue Jul 25 15:17:42 2017 +0200
+++ b/debian/changelog	Wed Sep 27 01:12:47 2017 +0200
@@ -1,8 +1,14 @@
-mercurial-evolve (6.5.0-1) UNRELEASED; urgency=medium
+mercurial-evolve (6.6.0-1) unstable; urgency=medium
 
   * new upstream release
 
- -- Pierre-Yves David <marmoute@nodosa.octopoid.net>  Sun, 02 Jul 2017 19:35:17 +0200
+ -- Pierre-Yves David <marmoute@nodosa.octopoid.net>  Tue, 25 Jul 2017 16:57:25 +0200
+
+mercurial-evolve (6.5.0-1) unstable; urgency=medium
+
+  * new upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@ens-lyon.org>  Sun, 02 Jul 2017 19:35:17 +0200
 
 mercurial-evolve (6.4.0-1) unstable; urgency=medium
 
--- a/docs/README	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/README	Wed Sep 27 01:12:47 2017 +0200
@@ -1,3 +1,22 @@
-doc generated with sphinx. tutorial exported using sphinxedhg
+Doc is generated with sphinx.
+
+You can generate the doc with:
+
+```
+make
+```
+
+# Tutorials
 
-http://hg.piranha.org.ua/sphinxedhg/
+For updating the tutorials, you need to have the docgraph extension installed
+(https://pypi.python.org/pypi/hg-docgraph).
+
+Then run the test-topic-tutorial.t and test-tutorial.t to update the output if
+needed.
+
+You'll need the dot binary (likely installed by the graphviz package in your
+package manager) in order to have graphviz graphs rendered in the html output.
+
+Simply run make in the docs directory should takes care of the conversion of
+the tutorial .t files into .rst files. Then sphinx should do the rest of the
+jobs by rendering graphviz graphs.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/commands.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,70 @@
+-------------------------
+Evolve Commands Reference
+-------------------------
+
+.. highlight:: none
+
+amend
+-----
+
+.. hghelp:: amend
+
+evolve
+------
+
+.. hghelp:: evolve
+
+fold
+----
+
+.. hghelp:: fold
+
+metaedit
+--------
+
+.. hghelp:: metaedit
+
+next
+----
+
+.. hghelp:: next
+
+obslog
+------
+
+.. hghelp:: obslog
+
+pdiff
+-----
+
+.. hghelp:: pdiff
+
+previous
+--------
+
+.. hghelp:: previous
+
+prune
+-----
+
+.. hghelp:: prune
+
+pstatus
+-------
+
+.. hghelp:: pstatus
+
+split
+-----
+
+.. hghelp:: split
+
+touch
+-----
+
+.. hghelp:: touch
+
+uncommit
+--------
+
+.. hghelp:: uncommit
--- a/docs/conf.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/conf.py	Wed Sep 27 01:12:47 2017 +0200
@@ -1,6 +1,16 @@
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+from mercurial import demandimport
+demandimport.disable()
+from docutils import nodes
+from docutils.parsers.rst import Directive
+from mercurial import ui
+from mercurial import extensions as hgext
+from mercurial import commands
+import os
+
+extensions = ["sphinx.ext.graphviz"]
+
 # autoclass_content = 'both'
 # Add any paths that contain templates here, relative to this directory.
 # templates_path = []
@@ -122,3 +132,28 @@
 
 # Output file base name for HTML help builder.
 # htmlhelp_basename = ''
+
+graphviz_output_format = "svg"
+
+class hghelpdirective(Directive):
+    has_content = True
+
+    def run(self):
+        u = ui.ui()
+        if not hasattr(u, 'disablepager'):
+            return []
+        u.disablepager()
+        u.setconfig(
+            'extensions', 'evolve',
+            os.path.join(
+                os.path.abspath(os.path.dirname(__file__)),
+                os.pardir, 'hgext3rd', 'evolve'))
+        hgext.loadall(u)
+        u.pushbuffer()
+        commands.help_(u, self.content[0])
+        return [
+            nodes.literal_block(text=u.popbuffer())]
+
+
+def setup(app):
+    app.add_directive('hghelp', hghelpdirective)
--- a/docs/index.rst	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/index.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -4,66 +4,98 @@
 Changeset Evolution with Mercurial
 ==================================
 
+`evolve`_ is a Mercurial extension for faster and safer mutable history. It
+implements the `changeset evolution`_ concept for `Mercurial`_.
+
+* It offers a safe and simple way to refine changesets locally and propagate
+  those changes to other repositories.
+
+* It can automatically detect and handle the complex issues that can arise from
+  exchanging draft changesets.
+
+* It even makes it possible for multiple developers to safely rewrite the same
+  parts of history in a distributed way.
+
+* It fully respects the Phases concept so users will only be able to rewrite
+  parts of the history that are safe to change. Phases have been part of
+  Mercurial since early 2012.
+
+.. _`evolve`: https://www.mercurial-scm.org/wiki/EvolveExtension
+.. _`Mercurial`: https://www.mercurial-scm.org/
+
+Installation and setup
+----------------------
+
+We recommend you subscribe to the `evolve-testers`_ mailing list to stay up
+to date with the latest news and announcement.
+
+.. _`evolve-testers`: https://www.mercurial-scm.org/mailman/listinfo/evolve-testers
+
+Using pip::
+
+    pip install --user hg-evolve
+
+Then add in your `hgrc` config::
+
+   [extensions]
+   evolve=
+
+You can easily edit the `hgrc` of a repository using `hg config --local`.
+Alternatively, you can edit your user configuration with `hg config --edit`.
+
+Table of Contents
+-----------------
+
 .. toctree::
    :maxdepth: 2
 
+   index
    user-guide
    sharing
    concepts
    from-mq
+   commands
+   known-doc-issues
 
-`evolve`_ is an experimental Mercurial extension for safe mutable history.
+.. _`changeset evolution`:
 
-.. _`evolve`: https://www.mercurial-scm.org/wiki/EvolveExtension
+What is Changeset Evolution?
+----------------------------
 
 With core Mercurial, changesets are permanent and immutable. You can
 commit new changesets to modify your source code, but you cannot
-modify or remove old changesets—they are carved in stone for all
-eternity.
-
-For years, Mercurial has included various extensions that allow
-history modification: ``rebase``, ``mq``, ``histedit``, and so forth.
-These are useful and popular extensions, and in fact history
-modification is one of the big reasons DVCSes (distributed version
-control systems) like Mercurial took off.
-
-But there's a catch: until now, Mercurial's various mechanisms for
-modifying history have been *unsafe*, in that changesets were
-destroyed (“stripped”) rather than simply made invisible.
+modify or remove old changesets.
 
-``evolve`` makes things better in a couple of ways:
+For years, Mercurial has included various commands that allow
+history modification: ``rebase``, ``histedit``, ``commit --amend`` and so forth.
+However, there's a catch: until now, Mercurial's various mechanisms for
+modifying history have been *unsafe*, in that changesets were
+destroyed (“stripped”) rather than simply hidden and still easy to recover.
 
-  * It changes the behaviour of most existing history modification
-    extensions (``rebase``, ``histedit``, etc.) so they use a safer
-    mechanism (*changeset obsolescence*, covered below) rather than
-    the older, less safe *strip* operation.
+``evolve`` makes things better by changing the behaviour of most existing
+history modification commands so they use a safer mechanism (*changeset
+obsolescence*, covered below) rather than the older, less safe *strip*
+operation.
 
-  * It provides a new way of modifying history that is roughly
-    equivalent to ``mq`` (but much nicer and safer).
-
-It helps to understand that ``evolve`` builds on infrastructure
-already in core Mercurial:
+``evolve`` is built on infrastructure in core Mercurial:
 
   * *Phases* (starting in Mercurial 2.1) allow you to distinguish
-    mutable and immutable changesets. We'll cover phases early in the
-    user guide, since understanding phases is essential to
-    understanding ``evolve``.
+    mutable and immutable changesets.
 
   * *Changeset obsolescence* (starting in Mercurial 2.3) is how
     Mercurial knows how history has been modified, specifically when
     one changeset replaces another. In the obsolescence model, a
     changeset is neither removed nor modified, but is instead marked
     *obsolete* and typically replaced by a *successor*. Obsolete
-    changesets usually become *hidden* as well. Obsolescence is an
-    invisible feature until you start using ``evolve``, so we'll cover
-    it in the user guide too.
+    changesets usually become *hidden* as well. Obsolescence is a
+    disabled feature in Mercurial until you start using ``evolve``.
 
 Some of the things you can do with ``evolve`` are:
 
   * Fix a mistake immediately: “Oops! I just committed a changeset
     with a syntax error—I'll fix that and amend the changeset so no
-    one sees my mistake.” (While this is possible using existing
-    features of core Mercurial, ``evolve`` makes it safer.)
+    one sees my mistake.” (While this is possible using default
+    features of core Mercurial, changeset evolution makes it safer.)
 
   * Fix a mistake a little bit later: “Oops! I broke the tests three
     commits back, but only noticed it now—I'll just update back to the
@@ -86,53 +118,49 @@
     for code review. The solution is to share mutable history with
     your reviewer, amending each changeset until it passes review.
 
-``evolve`` is experimental!
+  * Explore and audit the rewrite history of a changeset. Since Mercurial is
+    tracking the edits you make to a changeset, you can look at the history of
+    these edits. This is similar to Mercurial tracking the history of file
+    edits, but at the changeset level.
+
+Why the `evolve` extension?
 ---------------------------
 
-The long-term plan for ``evolve`` is to add it to core Mercurial.
-However, it is not yet stable enough for that. In particular:
-
-  * The UI is unstable: ``evolve``'s command names and command options
-    are not completely nailed down yet. They are subject to occasional
-    backwards-incompatible changes. If you write scripts that use
-    evolve commands, a future release could break your scripts.
+Mercurial core already has some support for `changeset evolution`_ so why have a
+dedicated extension?
 
-  * There are still some corner cases that aren't handled yet. If you
-    think you have found such a case, please check if it's already
-    described in the Mercurial bug tracker (https://bz.mercurial-scm.org/).
-    Bugs in ``evolve`` are files under component "evolution": use
-    `this query`_ to view open bugs in ``evolve``.
+The long-term plan for ``evolve`` is to add it to core Mercurial. However,
+having the extension helps us experiment with various user experience
+approaches and technical prototypes. Having a dedicated extension helps current
+users deploy the latest changes quickly and provides developers with low latency
+feedback.
 
-.. _`this query`: https://bz.mercurial-scm.org/buglist.cgi?component=evolution&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE
+Whenever we are happy with a experimental direction in the extension, the
+relevant code can go upstream into Core Mercurial.
 
-Installation and setup
-----------------------
-
-To use ``evolve``, you must:
+Development status
+------------------
 
-  #. Clone the ``evolve`` repository::
-
-       cd ~/src
-       hg clone https://www.mercurial-scm.org/repo/evolve
-
-  #. Configure the extension, either locally ::
-
-       hg config --local
-
-     or for all your repositories ::
+While well underway, the full implementation of the `changeset evolution`_
+concept is still a work in progress. Core Mercurial already supports many of the
+associated features, but for now they are still disabled by default. The current
+implementation has been usable for multiple years already, and some parts of it
+are used in production by multiple projects and companies (including the
+Mercurial project itself, Facebook, Google, etc…).
 
-       hg config --edit
-
-     Then add ::
-
-       evolve=~/src/evolve-main/hgext3rd/evolve/
+However, there are still some areas were the current implementation has gaps.
+This means some use cases or performance issues are not handled as well as they
+currently are without evolution. Mercurial has been around for a long time and
+is strongly committed to backward compatibility. Therefore turning evolution on
+by default today could regress the experience of some of our current users. The
+features will only be enabled by default at the point where users who do not use
+or care about the new features added by evolution won't be negatively impacted
+by the new default.
 
-     in the ``[extensions]`` section (adding the section if necessary). Use
-     the directory that you actually cloned to, of course.
+.. # .. _`this query`: https://bz.mercurial-scm.org/buglist.cgi?component=evolution&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE
 
-
-Next steps:
------------
+Resources
+---------
 
   * For a practical guide to using ``evolve`` in a single repository,
     see the `user guide`_.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/known-doc-issues.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,45 @@
+.. Copyright © 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
+
+==============================================
+Known limitations of the current documentation
+==============================================
+
+Features not covered by tutorials
+=================================
+
+Some of the *newer* features of evolution might not be reflected in the
+documentation yet. You can directly check the inline documentation of the
+extension itself for fresher details using `hg help -e evolve`.
+
+Known undocumented features are:
+
+ * `hg prev`,
+ * `hg next`,
+ * `hg next --evolve`,
+ * `hg evolve --rev`,
+ * `hg evolve --list`,
+ * `hg obslog`,
+ * `hg split`,
+ * `hg metaedit`,
+ * `hg touch`,
+ * `hg amend --extract`,
+ * `hg pdiff`,
+ * `hg pstatus`,
+ * `hg amend -i`,
+ * various topic related elements (in particular `hg stack`),
+
+Unreferenced Documents
+======================
+
+There are documents with content not linked in the flow of the main
+documentation. Some might be outdated and some are too fresh to be integrated in
+the main flow yet.
+
+.. toctree::
+   :maxdepth: 1
+
+   evolve-faq
+   evolve-good-practice
+   obs-terms
+   tutorials/topic-tutorial
+   tutorials/tutorial
--- a/docs/makefile	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/makefile	Wed Sep 27 01:12:47 2017 +0200
@@ -1,8 +1,11 @@
 
-all: tutorials/tutorial.rst static/logo-evolve.ico
+all: tutorials/tutorial.rst tutorials/topic-tutorial.rst static/logo-evolve.ico
 	sphinx-build . ../html/
 
-tutorials/tutorial.rst: tutorials/tutorial.t
+tutorials/tutorial.rst: tutorials/tutorial.t test2rst.py
+	python test2rst.py tutorials/
+
+tutorials/topic-tutorial.rst: tutorials/topic-tutorial.t test2rst.py
 	python test2rst.py tutorials/
 
 static/logo-evolve.ico: static/logo-evolve.svg
--- a/docs/obs-terms.rst	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/obs-terms.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -145,7 +145,7 @@
 |                     |                          | conflict)                   |
 |                     |                          |                             |
 |                     |                          | (possible alternative names:|
-|                     |                          | clashing, rival, concurent, |
+|                     |                          | clashing, rival, concurrent,|
 |                     |                          | conflicting)                |
 |                     |                          |                             |
 |                     +--------------------------+-----------------------------+
@@ -231,7 +231,7 @@
 This is an important name as hg pull/push will suggest it the same way it
 suggest merging when you add heads.
 
-alternative names:
+Alternative names:
 
 - solve (too generic ?)
 - stabilize
--- a/docs/sharing.rst	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/sharing.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -45,8 +45,8 @@
 your test server before anything is carved in stone.
 
 A less common scenario is multiple developers sharing mutable history,
-typically for code review. We'll cover this scenario later. But first,
-single-user sharing.
+typically for code review. We'll cover this scenario later. First, we
+will cover single-user sharing.
 
 Sharing with a single developer
 -------------------------------
@@ -55,10 +55,10 @@
 ==========================================
 
 The key to shared mutable history is to keep your changesets in
-*draft* phase as you pass them around. Recall that by default, ``hg
-push`` promotes changesets from *draft* to *public*, and public
+*draft* phase as you pass them around. Recall that by default,
+``hg push`` promotes changesets from *draft* to *public*, and public
 changesets are immutable. You can change this behaviour by
-reconfiguring the *target* repository so that it is non-publishing.
+reconfiguring the *remote* repository so that it is non-publishing.
 (Short version: set ``phases.publish`` to ``false``. Long version
 follows.)
 
@@ -90,7 +90,7 @@
 
 The key to shared mutable history is to make the target repository, in
 this case ``test-repo``, non-publishing. And, of course, we have to
-enable ``evolve`` in both ``test-repo`` and ``dev-repo``.
+enable the ``evolve`` extension in both ``test-repo`` and ``dev-repo``.
 
 First, edit the configuration for ``test-repo``::
 
@@ -102,7 +102,7 @@
   publish = false
 
   [extensions]
-  evolve = /path/to/evolve-main/hgext3rd/evolve/
+  evolve =
 
 Then edit the configuration for ``dev-repo``::
 
@@ -111,7 +111,7 @@
 and add ::
 
   [extensions]
-  evolve = /path/to/evolve-main/hgext3rd/evolve/
+  evolve =
 
 Keep in mind that in real life, these repositories would probably be
 on separate computers, so you'd have to login to each one to configure
@@ -203,7 +203,7 @@
 As seen in figure 3, this transfers the new changeset *and* the
 obsolescence marker for revision 1. However, it does *not* transfer
 the temporary amend commit, because it is hidden. Push and pull
-transfer obsolesence markers between repositories, but they do not
+transfer obsolescence markers between repositories, but they do not
 transfer hidden changesets.
 
   [figure SG03: dev-repo grows new rev 2:60ff, marks 1:f649 obsolete]
@@ -251,7 +251,7 @@
 .. _`concept guide`: concepts.html
 
 So the picture in ``public`` is much simpler than in either
-``dev-repo`` or ``test-repo``. Neither our missteps nor our amendments
+``dev-repo`` or ``test-repo``. Neither of our missteps nor our amendments
 are publicly visible, just the final, beautifully polished changeset:
 
   [figure SG05: public repo with rev 0:0dc9, 1:de61, both public]
@@ -331,7 +331,7 @@
 and add ::
 
   [extensions]
-  evolve = /path/to/evolve-main/hgext3rd/evolve/
+  evolve =
 
 Then edit Bob's repository configuration::
 
@@ -508,13 +508,13 @@
 but every competent chef keeps several around. Ever try to chop onions
 with a spoon?)
 
-In the user guide, we saw examples of *unstable* changesets, which are
+In the user guide, we saw examples of *unstbale* changesets, which are
 the most common type of troubled changeset. (Recall that a
-non-obsolete changeset with obsolete ancestors is unstable.)
+non-obsolete changeset with obsolete ancestors is an orphan.)
 
-Two other types of trouble can happen: *divergent* and *bumped*
-changesets. Both are more likely with shared mutable history,
-especially mutable history shared by multiple developers.
+Two other types of troubles can happen: *divergent* and
+*bumped* changesets. Both are more likely with shared mutable
+history, especially mutable history shared by multiple developers.
 
 Setting up
 ==========
@@ -545,7 +545,7 @@
 
   [extensions]
   rebase =
-  evolve = /path/to/evolve-main/hgext3rd/evolve/
+  evolve =
 
   [phases]
   publish = false
@@ -560,8 +560,8 @@
 ===============================
 
 When an obsolete changeset has two successors, those successors are
-*divergent*. One way to get into such a situation is by failing to
-communicate with your teammates. Let's see how that might happen.
+*divergent*. One way to get into such a situation is by failing
+to communicate with your teammates. Let's see how that might happen.
 
 First, we'll have Bob commit a bug fix that could still be improved::
 
@@ -621,22 +621,18 @@
 ``internal:local``. He's avoiding a `bug`_ in ``evolve`` that occurs
 when evolving divergent changesets using ``internal:local``.)
 
+# XXX this link does not work
 .. _`bug`: https://bitbucket.org/marmoute/mutable-history/issue/48/
 
 ** STOP HERE: WORK IN PROGRESS **
 
-Bumped changesets: only one gets on the plane
-=============================================
+Phase-divergence: when a rewritten changeset is made public
+===========================================================
 
-If two people show up at the airport with tickets for the same seat on
-the same plane, only one of them gets on the plane. The would-be
-traveller left behind in the airport terminal is said to have been
-*bumped*.
-
-Similarly, if Alice and Bob are collaborating on some mutable
+If Alice and Bob are collaborating on some mutable
 changesets, it's possible to get into a situation where an otherwise
 worthwhile changeset cannot be pushed to the public repository; it is
-bumped by an alternative changeset that happened to get there first.
+*phase-divergent* with another changeset that was made public first.
 Let's demonstrate one way this could happen.
 
 It starts with Alice committing a bug fix. Right now, we don't yet
@@ -676,21 +672,21 @@
 
 This introduces a contradiction: in Bob's repository, changeset 2:e011
 (his copy of Alice's fix) is obsolete, since Bob amended it. But in
-Alice's repository (and ``public``), that changeset is public: it is
-immutable, carved in stone for all eternity. No changeset can be both
-obsolete and public, so Bob is in for a surprise the next time he
-pulls from ``public``::
+Alice's repository (and the ``public`` repository), that changeset is
+public: it is immutable, carved in stone for all eternity. No changeset
+can be both obsolete and public, so Bob is in for a surprise the next
+time he pulls from ``public``::
 
   $ cd ../bob
   $ hg pull -q -u
-  1 new bumped changesets
+  1 new phase-divergent changesets
 
 Figure 7 shows what just happened to Bob's repository: changeset
 2:e011 is now public, so it can't be obsolete. When that changeset was
 obsolete, it made perfect sense for it to have a successor, namely
 Bob's amendment of Alice's fix (changeset 4:fe88). But it's illogical
-for a public changeset to have a successor, so 4:fe88 is in trouble:
-it has been *bumped*.
+for a public changeset to have a successor, so 4:fe88 is troubled:
+it has become *bumped*.
 
   [figure SG07: 2:e011 now public not obsolete, 4:fe88 now bumped]
 
@@ -699,7 +695,7 @@
 
   $ hg evolve --all
 
-Figure 8 illustrate's Bob's repository after evolving away the bumped
+Figure 8 illustrates Bob's repository after evolving away the bumped
 changeset. Ignoring the obsolete changesets, Bob now has a nice,
 clean, simple history. His amendment of Alice's bug fix lives on, as
 changeset 5:227d—albeit with a software-generated commit message. (Bob
@@ -718,8 +714,8 @@
 inattentive or careless user can do harm to himself or others.
 Mercurial with ``evolve`` goes to great lengths to limit the harm you
 can do by trying to handle all possible types of “troubled”
-changesets. But having a first-aid kit nearby does not excuse you from
-being careful with sharp knives.
+changesets. Nevertheless, having a first-aid kit nearby does not mean
+you should stop being careful with sharp knives.
 
 Mutable history shared across multiple repositories by a single
 developer is a natural extension of this model. Once you are used to
--- a/docs/test2rst.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/test2rst.py	Wed Sep 27 01:12:47 2017 +0200
@@ -1,15 +1,10 @@
 #!/usr/bin/env python
 
+import re
 import os
 import os.path as op
-import re
 import sys
 
-# line starts with two chars one of which is not a space (and both are not
-# newlines obviously) and ends with one or more newlines followed by two spaces
-# on a next line (indented text)
-CODEBLOCK = re.compile(r'()\n(([^ \n][^\n]|[^\n][^ \n])[^\n]*)\n+  ')
-
 INDEX = '''
 Mercurial tests
 ===============
@@ -18,12 +13,58 @@
    :maxdepth: 1
 '''
 
+ignored_patterns = [
+    re.compile('^#if'),
+    re.compile('^#else'),
+    re.compile('^#endif'),
+    re.compile('#rest-ignore$'),
+]
+
 
 def rstify(orig, name):
-    header = '%s\n%s\n\n' % (name, '=' * len(name))
-    content = header + orig
-    content = CODEBLOCK.sub(r'\n\1\n\n::\n\n  ', content)
-    return content
+    newlines = []
+
+    code_block_mode = False
+    sphinx_directive_mode = False
+
+    for line in orig.splitlines():
+
+        # Emtpy lines doesn't change output
+        if not line:
+            newlines.append(line)
+            code_block_mode = False
+            sphinx_directive_mode = False
+            continue
+
+        ignored = False
+        for pattern in ignored_patterns:
+            if pattern.search(line):
+                ignored = True
+                break
+        if ignored:
+            continue
+
+        # Sphinx directives mode
+        if line.startswith('  .. '):
+
+            # Insert a empty line to makes sphinx happy
+            newlines.append("")
+
+            # And unindent the directive
+            line = line[2:]
+            sphinx_directive_mode = True
+
+        # Code mode
+        codeline = line.startswith('  ')
+        if codeline and not sphinx_directive_mode:
+            if code_block_mode is False:
+                newlines.extend(['::', ''])
+
+            code_block_mode = True
+
+        newlines.append(line)
+
+    return "\n".join(newlines)
 
 
 def main(base):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/tutorials/topic-tutorial.t	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,1 @@
+../../tests/test-topic-tutorial.t
\ No newline at end of file
--- a/docs/user-guide.rst	Tue Jul 25 15:17:42 2017 +0200
+++ b/docs/user-guide.rst	Wed Sep 27 01:12:47 2017 +0200
@@ -26,17 +26,17 @@
 (``rebase``, ``histedit``, etc.), and also by the ``evolve``
 extension. Specifically, ``evolve`` adds a number of commands that can
 be used to modify history: ``amend``, ``uncommit``, ``prune``,
-``fold``, and ``evolve``. Generally speaking, changesets remain in
-*draft* phase until they are pushed to another repository, at which
-point they enter *public* phase. ::
+``fold``, and ``evolve``. ::
 
   $ hg commit -m 'implement feature X'
   $ hg phase -r .
   1: draft
 
-(Strictly speaking, changesets only become public when they are pushed
-to a *publishing* repository. But all repositories are publishing by
-default; you have to explicitly configure repositories to be
+Generally speaking, changesets remain in *draft* phase until they are
+pushed to another repository, at which point they enter the *public*
+phase. (Strictly speaking, changesets only become public when they are
+pushed to a *publishing* repository. But all repositories are publishing
+by default; you have to explicitly configure repositories to be
 *non-publishing*. Non-publishing repositories are an advanced topic
 which we'll see when we get to `sharing mutable history`_.)
 
@@ -60,7 +60,8 @@
 to create a new, amended changeset. The drawback of doing this with
 vanilla Mercurial is that your original, flawed, changeset is removed
 from the repository. This is *unsafe* history editing. It's probably
-not too serious if all you did was fix a syntax error, but still.
+not too serious if all you did was fix a syntax error, but for deeper
+changes there can be more serious consequences to unsafe history editing.
 
 .. figure:: figures/figure-ug01.svg
 
@@ -70,8 +71,9 @@
 (Incidentally, Mercurial's traditional history modification mechanism
 isn't *really* unsafe: any changeset(s) removed from the repository
 are kept in a backup directory, so you can manually restore them later
-if you change your mind. But it's awkward and inconvenient compared to
-the features provided by ``evolve`` and changeset obsolescence.)
+if you change your mind. However, this mechanism is very awkward and
+inconvenient compared to the features provided by ``evolve`` and
+changeset obsolescence.)
 
 Life with ``evolve`` (basic usage)
 ----------------------------------
@@ -99,7 +101,7 @@
 pass ``-m`` or ``-l``.)
 
 Under the hood, though, things are quite different. Mercurial has
-simply marked the old changeset *obsolete*, replacing it with a new
+simply marked the old changeset as *obsolete*, replacing it with a new
 one. We'll explore what this means in detail later, after working
 through a few more examples.
 
@@ -192,7 +194,7 @@
 
 and fold them::
 
-  $ hg fold -m 'fix bug 64' -r 7::
+  $ hg fold -m 'fix bug 64' -r 7:: --exact
   3 changesets folded
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
@@ -214,7 +216,7 @@
 When you have the ``evolve`` extension enabled, all history
 modification uses the same underlying mechanism: the original
 changesets are marked *obsolete* and replaced by zero or more
-*successors*. The obsolete changesets are the *precursors* of their
+*successors*. The obsolete changesets are the *predecessors* of their
 successors. This applies equally to built-in commands (``commit
 --amend``), commands added by ``evolve`` (``amend``, ``prune``,
 ``uncommit``, ``fold``), and commands provided by other extensions
@@ -232,7 +234,7 @@
 Consider Example 2, amending a changeset with ``evolve``. We saw above
 that you can do this using the exact same command-line syntax as core
 Mercurial, namely ``hg commit --amend``. But the implementation is
-quite different, and Figure 2 shows how.
+quite different, as Figure 2 shows.
 
 .. figure:: figures/figure-ug02.svg
 
@@ -243,8 +245,8 @@
    versions of Mercurial will not create them.)
 
 In this case, the obsolete changesets are also *hidden*. That is the
-usual end state for obsolete changesets. But many scenarios result in
-obsolete changesets that are still visible, which indicates your
+usual end state for obsolete changesets. However, many scenarios result
+in obsolete changesets that are still visible, which indicates your
 history modification work is not yet done. We'll see examples of that
 later, when we cover advanced usage.
 
@@ -287,7 +289,7 @@
 ``prune`` (example 4 above) is the simplest history modification
 command provided by ``evolve``. All it does is mark the specified
 changeset(s) obsolete, with no successor/precursor relationships
-involved. (If the working directory parent was one of the obsolete
+involved. (If the working directory parent was one of the obsoleted
 changesets, ``prune`` updates back to a suitable ancestor.)
 
 .. figure:: figures/figure-ug03.svg
@@ -299,11 +301,8 @@
 
 In one sense, ``uncommit`` is a simplified version of ``amend``. Like
 ``amend``, it obsoletes one changeset and leaves it with a single
-successor. Unlike ``amend``, there is no ugly "temporary amend commit"
-cluttering up the repository.
-
-In another sense, ``uncommit`` is the inverse of ``amend``: ``amend``
-takes any uncommitted changes in the working dir and “adds”
+successor. In another sense, ``uncommit`` is the inverse of ``amend``:
+``amend`` takes any uncommitted changes in the working dir and “adds”
 them to the working directory's parent changeset. (In reality, of
 course, it creates a successor changeset, marking the original
 obsolete.) In contrast, ``uncommit`` takes some changes in the working
@@ -341,8 +340,9 @@
 changesets.
 
 Note that all hidden changesets are obsolete: hidden is a subset of
-obsolete.
+obsolete. This is explained in more depth in the `concepts`_ section.
 
+.. _`concepts`: concepts.html
 
 Life with ``evolve`` (advanced usage)
 -------------------------------------
@@ -353,12 +353,12 @@
 which is an unavoidable consequence of obsolescence. What really sets
 ``evolve`` apart from other history modification mechanisms is the
 fact that it recognizes troubles like unstable changesets and provides
-a consistent way for you to get out of trouble.
+a consistent way for you to get back to a stable repository.
 
-(Incidentally, there are two other types of trouble that changesets
-can get into with ``evolve``: they may be *divergent* or *bumped*.
-Both of those states are more likely to occur when `sharing mutable
-history`_, so we won't see them in this user guide.)
+(Incidentally, there are two other types of troubles that changesets
+can get into with ``evolve``: they may be *divergent* or
+*bumped*. Both of those states are more likely to occur when
+`sharing mutable history`_, so we won't cover them in this user guide.)
 
 .. _`sharing mutable history`: sharing.html
 
@@ -366,8 +366,8 @@
 Example 7: Amend an older changeset
 ===================================
 
-Sometimes you don't notice your mistakes until after you have
-committed new changesets on top of them. ::
+Sometimes you don't notice a mistake until after you have committed
+new changesets on top of the changeset with the mistake. ::
 
   $ hg commit -m 'fix bug 17'         # rev 11 (mistake here)
   $ hg commit -m 'cleanup'            # rev 12
@@ -402,10 +402,10 @@
    descendants are *unstable*. The temporary amend commit, revision
    14, is hidden because it has no non-obsolete descendants.
 
-All non-obsolete descendants of an obsolete changeset are unstable. An
-interesting consequence of this is that revision 11 is still visible,
-even though it is obsolete. Obsolete changesets with non-obsolete
-descendants are not hidden.
+All non-obsolete descendants of an obsolete changeset are considered
+unstable. An interesting consequence of this is that revision 11 is
+still visible, even though it is obsolete. Obsolete changesets with
+non-obsolete descendants are not hidden.
 
 The fix is to *evolve* history::
 
@@ -415,9 +415,8 @@
 because there might be conflicts. If your amended changeset modifies a
 file that one of its descendants also modified, Mercurial has to fire
 up your merge tool to resolve the conflict. More importantly, you have
-to switch contexts from "writing code" to "resolving conflicts". That
-can be an expensive context switch, so Mercurial lets you decide when
-to do it.
+to switch from "writing code" to "resolving conflicts". That can be an
+expensive context switch, so Mercurial lets you decide when to do it.
 
 The end state, after ``evolve`` finishes, is that the original
 revisions (11-13) are obsolete and hidden. Their successor revisions
@@ -491,7 +490,7 @@
   M file2.c
 
 Now your repository has unstable changesets, so you need to evolve it.
-But ``hg evolve`` requires a clean working directory to resolve merge
+However, ``hg evolve`` requires a clean working directory to resolve merge
 conflicts, so you need to decide what to do with ``file2.c``.
 
 In this case, the change to ``file2.c`` was a temporary debugging
@@ -525,12 +524,12 @@
   $ hg commit -u dan -d '12 0' -m 'new feature'   # rev 27 (fine)
 
 As before, we update back to the flawed changeset (this time,
-revision 26) and ``uncommit``, leaving uncommitted changes to
+revision 26) and use ``uncommit``, leaving uncommitted changes to
 ``file2.c`` in the working dir::
 
   $ hg update -q 26
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg uncommit -q file2.c                        # obsoletes rev 26, creates rev 28
+  $ hg uncommit -q file2.c  # obsoletes rev 26, creates rev 28
   1 new unstable changesets
   $ hg status
   M file2.c
@@ -541,8 +540,8 @@
 
 Figure 11 shows the story so far: ``uncommit`` obsoleted revision 26
 and created revision 28, the successor of 26. Then we committed
-revision 29, a child of 28. We still have to deal with the unstable
-revision 27.
+revision 29, a child of 28. We still have to deal with the revision 27,
+which is an unstable changeset.
 
 .. figure:: figures/figure-ug11.svg
 
@@ -594,7 +593,7 @@
 The current implementation of ``hg touch`` is not ideal, and is likely to
 change in the future. Consider the history in Figure 12, where revision 27
 is obsolete and the child of 26, also obsolete. If we ``hg touch 27``, that
-creates a new revision which is a non-obsolete child of 26—i.e., it is
+creates a new revision which is a non-obsolete child of 26—i.e., it is an
 unstable. It's also *divergent*, another type of trouble that we'll learn
 about in the `next section`_.
 
--- a/hgext3rd/evolve/__init__.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/__init__.py	Wed Sep 27 01:12:47 2017 +0200
@@ -34,7 +34,7 @@
 help people transitioning. (The extensions is currently compatible down to
 Mercurial version 3.8).
 
-New Config:
+New Config::
 
     [experimental]
     # Set to control the behavior when pushing draft changesets to a publishing
@@ -103,7 +103,7 @@
 
 For very large repositories. it is currently recommended to disable obsmarkers
 discovery (Make sure you follow release announcement to know when you can turn
-it back on).
+it back on)::
 
     [experimental]
     evolution.obsdiscovery = no
@@ -137,7 +137,7 @@
   # evolution.effect-flags = false
 
 You can display the effect flags with the command obslog, so if you have a
-changeset and you update only the message, you will see:
+changeset and you update only the message, you will see::
 
     $ hg commit -m "WIP
     $ hg commit -m "A better commit message!"
@@ -271,7 +271,7 @@
     registrar.templatekeyword # new in hg-3.8
 except ImportError:
     from . import metadata
-    raise ImportError('evolve needs version %s or above' %
+    raise ImportError('evolve needs Mercurial version %s or above' %
                       min(metadata.testedwith.split()))
 
 import mercurial
@@ -458,11 +458,40 @@
 ### Useful alias
 
 @eh.uisetup
+def setupparentcommand(ui):
+
+    _alias, statuscmd = cmdutil.findcmd('status', commands.table)
+    pstatusopts = [o for o in statuscmd[1] if o[1] != 'rev']
+
+    @eh.command('pstatus', pstatusopts)
+    def pstatus(ui, repo, *args, **kwargs):
+        """show status combining committed and uncommited changes
+
+        This show the combined status of the current working copy parent commit and
+        the uncommitted change in the working copy itself. The status displayed
+        match the content of the commit that a bare :hg:`amend` will creates.
+
+        See :hg:`help status` for details."""
+        kwargs['rev'] = ['.^']
+        return statuscmd[0](ui, repo, *args, **kwargs)
+
+    _alias, diffcmd = cmdutil.findcmd('diff', commands.table)
+    pdiffopts = [o for o in diffcmd[1] if o[1] != 'rev']
+
+    @eh.command('pdiff', pdiffopts)
+    def pdiff(ui, repo, *args, **kwargs):
+        """show diff combining committed and uncommited changes
+
+        This show the combined diff of the current working copy parent commit and
+        the uncommitted change in the working copy itself. The diff displayed
+        match the content of the commit that a bare :hg:`amend` will creates.
+
+        See :hg:`help diff` for details."""
+        kwargs['rev'] = ['.^']
+        return diffcmd[0](ui, repo, *args, **kwargs)
+
+@eh.uisetup
 def _installalias(ui):
-    if ui.config('alias', 'pstatus', None) is None:
-        ui.setconfig('alias', 'pstatus', 'status --rev .^', 'evolve')
-    if ui.config('alias', 'pdiff', None) is None:
-        ui.setconfig('alias', 'pdiff', 'diff --rev .^', 'evolve')
     if ui.config('alias', 'odiff', None) is None:
         ui.setconfig('alias', 'odiff',
                      "diff --hidden --rev 'limit(precursors(.),1)' --rev .",
@@ -482,16 +511,15 @@
 
 ### Troubled revset symbol
 
-@eh.revset('troubled')
+@eh.revset('troubled()')
 def revsettroubled(repo, subset, x):
-    """``troubled()``
-    Changesets with troubles.
+    """Changesets with troubles.
     """
     revset.getargs(x, 0, 0, 'troubled takes no arguments')
     troubled = set()
-    troubled.update(getrevs(repo, 'unstable'))
-    troubled.update(getrevs(repo, 'bumped'))
-    troubled.update(getrevs(repo, 'divergent'))
+    troubled.update(getrevs(repo, 'orphan'))
+    troubled.update(getrevs(repo, 'phasedivergent'))
+    troubled.update(getrevs(repo, 'contentdivergent'))
     troubled = revset.baseset(troubled)
     troubled.sort() # set is non-ordered, enforce order
     return subset & troubled
@@ -504,7 +532,7 @@
     """Precursor of a changeset"""
     cs = set()
     nm = repo.changelog.nodemap
-    markerbysubj = repo.obsstore.precursors
+    markerbysubj = repo.obsstore.predecessors
     node = repo.changelog.node
     for r in s:
         for p in markerbysubj.get(node(r), ()):
@@ -519,7 +547,7 @@
     node = repo.changelog.node
     toproceed = [node(r) for r in s]
     seen = set()
-    allsubjects = repo.obsstore.precursors
+    allsubjects = repo.obsstore.predecessors
     while toproceed:
         nc = toproceed.pop()
         for mark in allsubjects.get(nc, ()):
@@ -589,10 +617,9 @@
 
 
 ### XXX I'm not sure this revset is useful
-@eh.revset('suspended')
+@eh.revset('suspended()')
 def revsetsuspended(repo, subset, x):
-    """``suspended()``
-    Obsolete changesets with non-obsolete descendants.
+    """Obsolete changesets with non-obsolete descendants.
     """
     revset.getargs(x, 0, 0, 'suspended takes no arguments')
     suspended = revset.baseset(getrevs(repo, 'suspended'))
@@ -600,10 +627,9 @@
     return subset & suspended
 
 
-@eh.revset('precursors')
+@eh.revset('precursors(set)')
 def revsetprecursors(repo, subset, x):
-    """``precursors(set)``
-    Immediate precursors of changesets in set.
+    """Immediate precursors of changesets in set.
     """
     s = revset.getset(repo, revset.fullreposet(repo), x)
     s = revset.baseset(_precursors(repo, s))
@@ -611,10 +637,9 @@
     return subset & s
 
 
-@eh.revset('allprecursors')
+@eh.revset('allprecursors(set)')
 def revsetallprecursors(repo, subset, x):
-    """``allprecursors(set)``
-    Transitive precursors of changesets in set.
+    """Transitive precursors of changesets in set.
     """
     s = revset.getset(repo, revset.fullreposet(repo), x)
     s = revset.baseset(_allprecursors(repo, s))
@@ -622,20 +647,18 @@
     return subset & s
 
 
-@eh.revset('successors')
+@eh.revset('successors(set)')
 def revsetsuccessors(repo, subset, x):
-    """``successors(set)``
-    Immediate successors of changesets in set.
+    """Immediate successors of changesets in set.
     """
     s = revset.getset(repo, revset.fullreposet(repo), x)
     s = revset.baseset(_successors(repo, s))
     s.sort()
     return subset & s
 
-@eh.revset('allsuccessors')
+@eh.revset('allsuccessors(set)')
 def revsetallsuccessors(repo, subset, x):
-    """``allsuccessors(set)``
-    Transitive successors of changesets in set.
+    """Transitive successors of changesets in set.
     """
     s = revset.getset(repo, revset.fullreposet(repo), x)
     s = revset.baseset(_allsuccessors(repo, s))
@@ -670,7 +693,7 @@
     if reason == 'pruned':
         solvemsg = _("use 'hg evolve' to update to its parent successor")
     elif reason == 'diverged':
-        debugcommand = "hg evolve --list --divergent"
+        debugcommand = "hg evolve --list --contentdivergent"
         basemsg = _("%s has diverged, use '%s' to resolve the issue")
         solvemsg = basemsg % (shortnode, debugcommand)
     elif reason == 'superseed':
@@ -759,23 +782,25 @@
     # part of the troubled stuff may be filtered (stash ?)
     # This needs a better implementation but will probably wait for core.
     filtered = repo.changelog.filteredrevs
-    priorunstables = len(set(getrevs(repo, 'unstable')) - filtered)
-    priorbumpeds = len(set(getrevs(repo, 'bumped')) - filtered)
-    priordivergents = len(set(getrevs(repo, 'divergent')) - filtered)
+    priorunstables = len(set(getrevs(repo, 'orphan')) - filtered)
+    priorbumpeds = len(set(getrevs(repo, 'phasedivergent')) - filtered)
+    priordivergents = len(set(getrevs(repo, 'contentdivergent')) - filtered)
     ret = orig(ui, repo, *args, **kwargs)
     filtered = repo.changelog.filteredrevs
     newunstables = \
-        len(set(getrevs(repo, 'unstable')) - filtered) - priorunstables
+        len(set(getrevs(repo, 'orphan')) - filtered) - priorunstables
     newbumpeds = \
-        len(set(getrevs(repo, 'bumped')) - filtered) - priorbumpeds
+        len(set(getrevs(repo, 'phasedivergent')) - filtered) - priorbumpeds
     newdivergents = \
-        len(set(getrevs(repo, 'divergent')) - filtered) - priordivergents
+        len(set(getrevs(repo, 'contentdivergent')) - filtered) - priordivergents
+
+    base_msg = _('%i new %s changesets\n')
     if newunstables > 0:
-        ui.warn(_('%i new unstable changesets\n') % newunstables)
+        ui.warn(base_msg % (newunstables, compat.TROUBLES['ORPHAN']))
     if newbumpeds > 0:
-        ui.warn(_('%i new bumped changesets\n') % newbumpeds)
+        ui.warn(base_msg % (newbumpeds, compat.TROUBLES['PHASEDIVERGENT']))
     if newdivergents > 0:
-        ui.warn(_('%i new divergent changesets\n') % newdivergents)
+        ui.warn(base_msg % (newdivergents, compat.TROUBLES['CONTENTDIVERGENT']))
     return ret
 
 @eh.wrapfunction(mercurial.exchange, 'push')
@@ -977,7 +1002,7 @@
         ui = args[0]
         ui.warn(deprecationwarning)
         util.checksignature(fn)(*args, **kwargs)
-    newfn.__doc__ = deprecationwarning
+    newfn.__doc__ = deprecationwarning + ' (DEPRECATED)'
     cmdwrapper = eh.command(oldalias, opts, synopsis)
     cmdwrapper(newfn)
 
@@ -993,11 +1018,11 @@
         wlock = repo.wlock()
         lock = repo.lock()
         tr = repo.transaction("evolve")
-        if 'unstable' == category:
+        if 'orphan' == category:
             result = _solveunstable(ui, repo, ctx, dryrun, confirm, progresscb)
-        elif 'bumped' == category:
+        elif 'phasedivergent' == category:
             result = _solvebumped(ui, repo, ctx, dryrun, confirm, progresscb)
-        elif 'divergent' == category:
+        elif 'contentdivergent' == category:
             result = _solvedivergent(ui, repo, ctx, dryrun, confirm,
                                      progresscb)
         else:
@@ -1010,37 +1035,44 @@
 def _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat):
     """Used by the evolve function to display an error message when
     no troubles can be resolved"""
-    troublecategories = ['bumped', 'divergent', 'unstable']
+    troublecategories = ['phasedivergent', 'contentdivergent', 'orphan']
     unselectedcategories = [c for c in troublecategories if c != targetcat]
     msg = None
     hint = None
 
     troubled = {
-        "unstable": repo.revs("unstable()"),
-        "divergent": repo.revs("divergent()"),
-        "bumped": repo.revs("bumped()"),
+        "orphan": repo.revs("orphan()"),
+        "contentdivergent": repo.revs("contentdivergent()"),
+        "phasedivergent": repo.revs("phasedivergent()"),
         "all": repo.revs("troubled()"),
     }
 
     hintmap = {
-        'bumped': _("do you want to use --bumped"),
-        'bumped+divergent': _("do you want to use --bumped or --divergent"),
-        'bumped+unstable': _("do you want to use --bumped or --unstable"),
-        'divergent': _("do you want to use --divergent"),
-        'divergent+unstable': _("do you want to use --divergent"
-                                " or --unstable"),
-        'unstable': _("do you want to use --unstable"),
-        'any+bumped': _("do you want to use --any (or --rev) and --bumped"),
-        'any+bumped+divergent': _("do you want to use --any (or --rev) and"
-                                  " --bumped or --divergent"),
-        'any+bumped+unstable': _("do you want to use --any (or --rev) and"
-                                 "--bumped or --unstable"),
-        'any+divergent': _("do you want to use --any (or --rev) and"
-                           " --divergent"),
-        'any+divergent+unstable': _("do you want to use --any (or --rev)"
-                                    " and --divergent or --unstable"),
-        'any+unstable': _("do you want to use --any (or --rev)"
-                          "and --unstable"),
+        'phasedivergent': _("do you want to use --phasedivergent"),
+        'phasedivergent+contentdivergent': _("do you want to use "
+                                             "--phasedivergent or"
+                                             " --contentdivergent"),
+        'phasedivergent+orphan': _("do you want to use --phasedivergent"
+                                   " or --orphan"),
+        'contentdivergent': _("do you want to use --contentdivergent"),
+        'contentdivergent+orphan': _("do you want to use --contentdivergent"
+                                     " or --orphan"),
+        'orphan': _("do you want to use --orphan"),
+        'any+phasedivergent': _("do you want to use --any (or --rev) and"
+                                " --phasedivergent"),
+        'any+phasedivergent+contentdivergent': _("do you want to use --any"
+                                                 " (or --rev) and"
+                                                 " --phasedivergent or"
+                                                 " --contentdivergent"),
+        'any+phasedivergent+orphan': _("do you want to use --any (or --rev)"
+                                       " and --phasedivergent or --orphan"),
+        'any+contentdivergent': _("do you want to use --any (or --rev) and"
+                                  " --contentdivergent"),
+        'any+contentdivergent+orphan': _("do you want to use --any (or --rev)"
+                                         " and --contentdivergent or "
+                                         "--orphan"),
+        'any+orphan': _("do you want to use --any (or --rev)"
+                        "and --orphan"),
     }
 
     if revopt:
@@ -1067,7 +1099,7 @@
 
     else:
         # evolve without any option = relative to the current wdir
-        if targetcat == 'unstable':
+        if targetcat == 'orphan':
             msg = _("nothing to evolve on current working copy parent")
         else:
             msg = _("current working copy parent is not %s") % targetcat
@@ -1183,6 +1215,11 @@
         discarded.update(othersrevs)
     return res
 
+instabilities_map = {
+    'contentdivergent': "content-divergent",
+    'phasedivergent': "phase-divergent"
+}
+
 def _selectrevs(repo, allopt, revopt, anyopt, targetcat):
     """select troubles in repo matching according to given options"""
     revs = set()
@@ -1194,23 +1231,23 @@
             topic = getattr(repo, 'currenttopic', '')
             if topic:
                 revs = repo.revs('topic(%s)', topic) & revs
-            elif targetcat == 'unstable':
+            elif targetcat == 'orphan':
                 revs = _aspiringdescendant(repo,
                                            repo.revs('(.::) - obsolete()::'))
                 revs = set(revs)
-        if targetcat == 'divergent':
+        if targetcat == 'contentdivergent':
             # Pick one divergent per group of divergents
             revs = _dedupedivergents(repo, revs)
     elif anyopt:
         revs = repo.revs('first(%s())' % (targetcat))
-    elif targetcat == 'unstable':
+    elif targetcat == 'orphan':
         revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::')))
         if 1 < len(revs):
             msg = "multiple evolve candidates"
             hint = (_("select one of %s with --rev")
                     % ', '.join([str(repo[r]) for r in sorted(revs)]))
             raise error.Abort(msg, hint=hint)
-    elif targetcat in repo['.'].troubles():
+    elif instabilities_map.get(targetcat, targetcat) in repo['.'].instabilities():
         revs = set([repo['.'].rev()])
     return revs
 
@@ -1287,10 +1324,10 @@
 
 def listtroubles(ui, repo, troublecategories, **opts):
     """Print all the troubles for the repo (or given revset)"""
-    troublecategories = troublecategories or ['divergent', 'unstable', 'bumped']
-    showunstable = 'unstable' in troublecategories
-    showbumped = 'bumped' in troublecategories
-    showdivergent = 'divergent' in troublecategories
+    troublecategories = troublecategories or ['contentdivergent', 'orphan', 'phasedivergent']
+    showunstable = 'orphan' in troublecategories
+    showbumped = 'phasedivergent' in troublecategories
+    showdivergent = 'contentdivergent' in troublecategories
 
     revs = repo.revs('+'.join("%s()" % t for t in troublecategories))
     if opts.get('rev'):
@@ -1299,7 +1336,7 @@
     fm = ui.formatter('evolvelist', opts)
     for rev in revs:
         ctx = repo[rev]
-        unpars = _preparelistctxs(ctx.parents(), lambda p: p.unstable())
+        unpars = _preparelistctxs(ctx.parents(), lambda p: p.orphan())
         obspars = _preparelistctxs(ctx.parents(), lambda p: p.obsolete())
         imprecs = _preparelistctxs(repo.set("allprecursors(%n)", ctx.node()),
                                    lambda p: not p.mutable())
@@ -1317,7 +1354,7 @@
         fm.data(node=ctx.hex(), rev=ctx.rev(), desc=desc, phase=ctx.phasestr())
 
         for unpar in unpars if showunstable else []:
-            fm.plain('  unstable: %s (unstable parent)\n' % unpar[:hashlen])
+            fm.plain('  orphan: %s (orphan parent)\n' % unpar[:hashlen])
         for obspar in obspars if showunstable else []:
             fm.plain('  unstable: %s (obsolete parent)\n' % obspar[:hashlen])
         for imprec in imprecs if showbumped else []:
@@ -1369,8 +1406,11 @@
         'directory')),
      ('r', 'rev', [], _('solves troubles of these revisions')),
      ('', 'bumped', False, _('solves only bumped changesets')),
+     ('', 'phasedivergent', False, _('solves only phase-divergent changesets')),
      ('', 'divergent', False, _('solves only divergent changesets')),
-     ('', 'unstable', False, _('solves only unstable changesets (default)')),
+     ('', 'contentdivergent', False, _('solves only content-divergent changesets')),
+     ('', 'unstable', False, _('solves only unstable changesets')),
+     ('', 'orphan', False, _('solves only orphan changesets (default)')),
      ('a', 'all', False, _('evolve all troubled changesets related to the '
                            'current  working directory and its descendants')),
      ('c', 'continue', False, _('continue an interrupted evolution')),
@@ -1457,13 +1497,36 @@
     dryrunopt = opts['dry_run']
     confirmopt = opts['confirm']
     revopt = opts['rev']
-    troublecategories = ['bumped', 'divergent', 'unstable']
+
+    # Backward compatibility
+    if opts['unstable']:
+        msg = ("'evolve --unstable' is deprecated, "
+               "use 'evolve --orphan'")
+        repo.ui.deprecwarn(msg, '4.4')
+
+        opts['orphan'] = opts['divergent']
+
+    if opts['divergent']:
+        msg = ("'evolve --divergent' is deprecated, "
+               "use 'evolve --contentdivergent'")
+        repo.ui.deprecwarn(msg, '4.4')
+
+        opts['contentdivergent'] = opts['divergent']
+
+    if opts['bumped']:
+        msg = ("'evolve --bumped' is deprecated, "
+               "use 'evolve --phasedivergent'")
+        repo.ui.deprecwarn(msg, '4.4')
+
+        opts['phasedivergent'] = opts['bumped']
+
+    troublecategories = ['phasedivergent', 'contentdivergent', 'orphan']
     specifiedcategories = [t for t in troublecategories if opts[t]]
     if listopt:
         listtroubles(ui, repo, specifiedcategories, **opts)
         return
 
-    targetcat = 'unstable'
+    targetcat = 'orphan'
     if 1 < len(specifiedcategories):
         msg = _('cannot specify more than one trouble category to solve (yet)')
         raise error.Abort(msg)
@@ -1543,7 +1606,7 @@
     # For the progress bar to show
     count = len(revs)
     # Order the revisions
-    if targetcat == 'unstable':
+    if targetcat == 'orphan':
         revs = _orderrevs(repo, revs)
     for rev in revs:
         progresscb()
@@ -1580,7 +1643,7 @@
     one of its descendants. Empty list if none can be found."""
     target = set(revs)
     result = []
-    for r in repo.revs('unstable() - %ld', revs):
+    for r in repo.revs('orphan() - %ld', revs):
         dest = _possibledestination(repo, r)
         if target & dest:
             result.append(r)
@@ -1592,7 +1655,7 @@
     target = set(revs)
     result = set(target)
     paths = collections.defaultdict(set)
-    for r in repo.revs('unstable() - %ld', revs):
+    for r in repo.revs('orphan() - %ld', revs):
         for d in _possibledestination(repo, r):
             paths[d].add(r)
 
@@ -2131,7 +2194,7 @@
             else:
                 cmdutil.bailifchanged(repo)
                 result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
-                                   False, lambda: None, category='unstable')
+                                   False, lambda: None, category='orphan')
                 if not result:
                     ui.status(_('working directory now at %s\n')
                               % ui.label(str(repo['.']), 'evolve.node'))
--- a/hgext3rd/evolve/cmdrewrite.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/cmdrewrite.py	Wed Sep 27 01:12:47 2017 +0200
@@ -24,6 +24,7 @@
     lock as lockmod,
     node,
     obsolete,
+    patch,
     phases,
     scmutil,
     util,
@@ -44,6 +45,7 @@
 commitopts = commands.commitopts
 commitopts2 = commands.commitopts2
 mergetoolopts = commands.mergetoolopts
+stringio = util.stringio
 
 # option added by evolve
 
@@ -98,9 +100,6 @@
     """
     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):
@@ -187,7 +186,7 @@
     newid = repo.commitctx(new)
     return newid
 
-def _uncommitdirstate(repo, oldctx, match):
+def _uncommitdirstate(repo, oldctx, match, interactive):
     """Fix the dirstate after switching the working directory from
     oldctx to a copy of oldctx not containing changed files matched by
     match.
@@ -195,29 +194,82 @@
     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)
+    if interactive:
+        # In interactive cases, we will find the status between oldctx and ctx
+        # and considering only the files which are changed between oldctx and
+        # ctx, and the status of what changed between oldctx and ctx will help
+        # us in defining the exact behavior
+        m, a, r = repo.status(oldctx, ctx, match=match)[:3]
+        for f in m:
+            # These are files which are modified between oldctx and ctx which
+            # contains two cases: 1) Were modified in oldctx and some
+            # modifications are uncommitted
+            # 2) Were added in oldctx but some part is uncommitted (this cannot
+            # contain the case when added files are uncommitted completely as
+            # that will result in status as removed not modified.)
+            # Also any modifications to a removed file will result the status as
+            # added, so we have only two cases. So in either of the cases, the
+            # resulting status can be modified or clean.
+            if ds[f] == 'r':
+                # But the file is removed in the working directory, leaving that
+                # as removed
+                continue
+            ds.normallookup(f)
+
+        for f in a:
+            # These are the files which are added between oldctx and ctx(new
+            # one), which means the files which were removed in oldctx
+            # but uncommitted completely while making the ctx
+            # This file should be marked as removed if the working directory
+            # does not adds it back. If it's adds it back, we do a normallookup.
+            # The file can't be removed in working directory, because it was
+            # removed in oldctx
+            if ds[f] == 'a':
+                ds.normallookup(f)
+                continue
+            ds.remove(f)
 
-    for f in a:
-        if ds[f] == 'r':
-            # added + removed -> unknown
-            ds.drop(f)
-        elif ds[f] != 'a':
+        for f in r:
+            # These are files which are removed between oldctx and ctx, which
+            # means the files which were added in oldctx and were completely
+            # uncommitted in ctx. If a added file is partially uncommitted, that
+            # would have resulted in modified status, not removed.
+            # So a file added in a commit, and uncommitting that addition must
+            # result in file being stated as unknown.
+            if ds[f] == 'r':
+                # The working directory say it's removed, so lets make the file
+                # unknown
+                ds.drop(f)
+                continue
             ds.add(f)
+    else:
+        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 r:
-        if ds[f] == 'a':
-            # removed + added -> normal
-            ds.normallookup(f)
-        elif ds[f] != 'r':
-            ds.remove(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 = {}
+    if interactive:
+        # Interactive had different meaning of the variables so restoring the
+        # original meaning to use them
+        m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
     for f in (m + a):
         src = oldctx[f].renamed()
         if src:
@@ -234,6 +286,7 @@
 @eh.command(
     '^uncommit',
     [('a', 'all', None, _('uncommit all changes when no arguments given')),
+     ('i', 'interactive', False, _('interactive mode to uncommit (EXPERIMENTAL)')),
      ('r', 'rev', '', _('revert commit content to REV instead')),
      ] + commands.walkopts + commitopts + commitopts2 + commitopts3,
     _('[OPTION]... [NAME]'))
@@ -252,10 +305,16 @@
     revision. It still does not change the content of your file in the working
     directory.
 
+    .. container:: verbose
+
+       The --interactive option lets you select hunks interactively to uncommit.
+       You can uncommit parts of file using this option.
+
     Return 0 if changed files are uncommitted.
     """
 
     _resolveoptions(ui, opts) # process commitopts3
+    interactive = opts.get('interactive')
     wlock = lock = tr = None
     try:
         wlock = repo.wlock()
@@ -287,25 +346,30 @@
         # Recommit the filtered changeset
         tr = repo.transaction('uncommit')
         updatebookmarks = rewriteutil.bookmarksupdater(repo, old.node(), tr)
-        newid = None
-        includeorexclude = opts.get('include') or opts.get('exclude')
-        if (pats or includeorexclude or opts.get('all')):
+        if interactive:
+            opts['all'] = True
             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
+            newid = _interactiveuncommit(ui, repo, old, match)
+        else:
+            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"))
+
         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)
+            _uncommitdirstate(repo, old, match, interactive)
         updatebookmarks(newid)
         if not repo[newid].files():
             ui.warn(_("new changeset is empty\n"))
@@ -314,6 +378,101 @@
     finally:
         lockmod.release(tr, lock, wlock)
 
+def _interactiveuncommit(ui, repo, old, match):
+    """ The function which contains all the logic for interactively uncommiting
+    a commit. This function makes a temporary commit with the chunks which user
+    selected to uncommit. After that the diff of the parent and that commit is
+    applied to the working directory and committed again which results in the
+    new commit which should be one after uncommitted.
+    """
+
+    # create a temporary commit with hunks user selected
+    tempnode = _createtempcommit(ui, repo, old, match)
+
+    diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
+    diffopts.nodates = True
+    diffopts.git = True
+    fp = stringio()
+    for chunk, label in patch.diffui(repo, tempnode, old.node(), None,
+                                     opts=diffopts):
+            fp.write(chunk)
+
+    fp.seek(0)
+    newnode = _patchtocommit(ui, repo, old, fp)
+    # creating obs marker temp -> ()
+    obsolete.createmarkers(repo, [(repo[tempnode], ())])
+    return newnode
+
+def _createtempcommit(ui, repo, old, match):
+    """ Creates a temporary commit for `uncommit --interative` which contains
+    the hunks which were selected by the user to uncommit.
+    """
+
+    pold = old.p1()
+    # The logic to interactively selecting something copied from
+    # cmdutil.revert()
+    diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
+    diffopts.nodates = True
+    diffopts.git = True
+    diff = patch.diff(repo, pold.node(), old.node(), match, opts=diffopts)
+    originalchunks = patch.parsepatch(diff)
+    # XXX: The interactive selection is buggy and does not let you
+    # uncommit a removed file partially.
+    # TODO: wrap the operations in mercurial/patch.py and mercurial/crecord.py
+    # to add uncommit as an operation taking care of BC.
+    chunks, opts = cmdutil.recordfilter(repo.ui, originalchunks,
+                                        operation='discard')
+    if not chunks:
+        raise error.Abort(_("nothing selected to uncommit"))
+    fp = stringio()
+    for c in chunks:
+            c.write(fp)
+
+    fp.seek(0)
+    oldnode = node.hex(old.node())[:12]
+    message = 'temporary commit for uncommiting %s' % oldnode
+    tempnode = _patchtocommit(ui, repo, old, fp, message, oldnode)
+    return tempnode
+
+def _patchtocommit(ui, repo, old, fp, message=None, extras=None):
+    """ A function which will apply the patch to the working directory and
+    make a commit whose parents are same as that of old argument. The message
+    argument tells us whether to use the message of the old commit or a
+    different message which is passed. Returns the node of new commit made.
+    """
+    pold = old.p1()
+    parents = (old.p1().node(), old.p2().node())
+    date = old.date()
+    branch = old.branch()
+    user = old.user()
+    extra = old.extra()
+    if extras:
+        extra['uncommit_source'] = extras
+    if not message:
+        message = old.description()
+    store = patch.filestore()
+    try:
+        files = set()
+        try:
+            patch.patchrepo(ui, repo, pold, store, fp, 1, '',
+                            files=files, eolmode=None)
+        except patch.PatchError as err:
+            raise error.Abort(str(err))
+
+        finally:
+            del fp
+
+        memctx = context.memctx(repo, parents, message, files=files,
+                                filectxfn=store,
+                                user=user,
+                                date=date,
+                                branch=branch,
+                                extra=extra)
+        newcm = memctx.commit()
+    finally:
+        store.close()
+    return newcm
+
 @eh.command(
     '^fold|squash',
     [('r', 'rev', [], _("revision to fold")),
@@ -350,7 +509,7 @@
 
          hg fold --from 3::6
 
-     - Fold revisions 3 and 4:
+     - Fold revisions 3 and 4::
 
         hg fold "3 + 4" --exact
 
--- a/hgext3rd/evolve/compat.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/compat.py	Wed Sep 27 01:12:47 2017 +0200
@@ -7,8 +7,10 @@
 """
 
 from mercurial import (
+    context,
     hg,
     obsolete,
+    revset,
     util,
 )
 
@@ -45,7 +47,7 @@
         pendingnodes = set(nodes)
         seenmarkers = set()
         seennodes = set(pendingnodes)
-        precursorsmarkers = self.precursors
+        precursorsmarkers = self.predecessors
         succsmarkers = self.successors
         children = self.children
         while pendingnodes:
@@ -71,10 +73,13 @@
     return func(*args, **kwargs)
 
 # allprecursors set move from mercurial.obsolete to mercurial.obsutil in 4.3
+# allprecursors  was renamed into allpredecessors in 4.4
 def allprecursors(*args, **kwargs):
-    func = getattr(obsutil, 'allprecursors', None)
+    func = getattr(obsutil, 'allpredecessors', None)
     if func is None:
-        func = obsolete.allprecursors
+        func = getattr(obsutil, 'allprecursors', None)
+        if func is None:
+            func = obsolete.allprecursors
     return func(*args, **kwargs)
 
 # compatibility layer for mercurial < 4.3
@@ -90,3 +95,80 @@
         else:
             bookmarks[name] = node
     bookmarks.recordchange(tr)
+
+# Evolution renaming compat
+
+TROUBLES = {}
+
+if not util.safehasattr(context.basectx, 'orphan'):
+    TROUBLES['ORPHAN'] = 'unstable'
+    context.basectx.orphan = context.basectx.unstable
+else:
+    TROUBLES['ORPHAN'] = 'orphan'
+
+if not util.safehasattr(context.basectx, 'contentdivergent'):
+    TROUBLES['CONTENTDIVERGENT'] = 'divergent'
+    context.basectx.contentdivergent = context.basectx.divergent
+else:
+    TROUBLES['CONTENTDIVERGENT'] = 'content-divergent'
+
+if not util.safehasattr(context.basectx, 'phasedivergent'):
+    TROUBLES['PHASEDIVERGENT'] = 'bumped'
+    context.basectx.phasedivergent = context.basectx.bumped
+else:
+    TROUBLES['PHASEDIVERGENT'] = 'phase-divergent'
+
+if not util.safehasattr(context.basectx, 'isunstable'):
+    context.basectx.isunstable = context.basectx.troubled
+
+if not util.safehasattr(revset, 'orphan'):
+    @eh.revset('orphan')
+    def oprhanrevset(*args, **kwargs):
+        return revset.unstable(*args, **kwargs)
+
+if not util.safehasattr(revset, 'contentdivergent'):
+    @eh.revset('contentdivergent')
+    def contentdivergentrevset(*args, **kwargs):
+        return revset.divergent(*args, **kwargs)
+
+if not util.safehasattr(revset, 'phasedivergent'):
+    @eh.revset('phasedivergent')
+    def phasedivergentrevset(*args, **kwargs):
+        return revset.bumped(*args, **kwargs)
+
+if not util.safehasattr(context.basectx, 'instabilities'):
+    def instabilities(self):
+        """return the list of instabilities affecting this changeset.
+
+        Instabilities are returned as strings. possible values are:
+         - orphan,
+         - phase-divergent,
+         - content-divergent.
+         """
+        instabilities = []
+        if self.orphan():
+            instabilities.append('orphan')
+        if self.phasedivergent():
+            instabilities.append('phase-divergent')
+        if self.contentdivergent():
+            instabilities.append('content-divergent')
+        return instabilities
+
+    context.basectx.instabilities = instabilities
+
+# XXX: Better detection of property cache
+if 'predecessors' not in dir(obsolete.obsstore):
+    @property
+    def predecessors(self):
+        return self.precursors
+
+    obsolete.obsstore.predecessors = predecessors
+
+if not util.safehasattr(obsolete, '_computeorphanset'):
+    obsolete._computeorphanset = obsolete.cachefor('orphan')(obsolete._computeunstableset)
+
+if not util.safehasattr(obsolete, '_computecontentdivergentset'):
+    obsolete._computecontentdivergentset = obsolete.cachefor('contentdivergent')(obsolete._computedivergentset)
+
+if not util.safehasattr(obsolete, '_computephasedivergentset'):
+    obsolete._computephasedivergentset = obsolete.cachefor('phasedivergent')(obsolete._computebumpedset)
--- a/hgext3rd/evolve/exthelper.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/exthelper.py	Wed Sep 27 01:12:47 2017 +0200
@@ -93,10 +93,17 @@
         - Register revset functions
         """
         knownexts = {}
+
+        revsetpredicate = registrar.revsetpredicate()
         for name, symbol in self._revsetsymbols:
-            revset.symbols[name] = symbol
+            revsetpredicate(name)(symbol)
+        revset.loadpredicate(ui, 'evolve', revsetpredicate)
+
+        templatekeyword = registrar.templatekeyword()
         for name, kw in self._templatekws:
-            templatekw.keywords[name] = kw
+            templatekeyword(name)(kw)
+        templatekw.loadkeyword(ui, 'evolve', templatekeyword)
+
         for ext, command, wrapper, opts in self._extcommandwrappers:
             if ext not in knownexts:
                 try:
--- a/hgext3rd/evolve/hack/directaccess.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/hack/directaccess.py	Wed Sep 27 01:12:47 2017 +0200
@@ -155,12 +155,12 @@
         return []
 
     results = []
-    if len(tree) == 2 and tree[0] == "symbol":
+    if len(tree) in (2, 3) and tree[0] == "symbol":
         results.append(tree[1])
     elif tree[0] == "func" and tree[1] == _listtuple:
         # the optimiser will group sequence of hash request
         results += tree[2][1].split('\0')
-    elif len(tree) >= 3:
+    elif len(tree) >= 2:
         for subtree in tree[1:]:
             results += gethashsymbols(subtree, maxrev)
         # return directly, we don't need to filter symbols again
--- a/hgext3rd/evolve/hack/drophack.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/hack/drophack.py	Wed Sep 27 01:12:47 2017 +0200
@@ -50,7 +50,7 @@
     seennodes = set(nodes)
     seenmarkers = set()
     pendingnodes = set(nodes)
-    precursorsmarkers = obsstore.precursors
+    precursorsmarkers = obsstore.predecessors
     while pendingnodes:
         current = pendingnodes.pop()
         new = set()
--- a/hgext3rd/evolve/metadata.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/metadata.py	Wed Sep 27 01:12:47 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.6.0'
+__version__ = '6.7.0.dev'
 testedwith = '3.8.4 3.9.2 4.0.2 4.1.3 4.2.2'
 minimumhgversion = '3.8'
 buglink = 'https://bz.mercurial-scm.org/'
--- a/hgext3rd/evolve/obscache.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/obscache.py	Wed Sep 27 01:12:47 2017 +0200
@@ -111,21 +111,26 @@
 
     return obsstore
 
-# XXX copied as is from Mercurial 4.2 and added the "offset" parameters
-@util.nogc
-def _readmarkers(data, offset=None):
-    """Read and enumerate markers from raw data"""
-    off = 0
-    diskversion = struct.unpack('>B', data[off:off + 1])[0]
-    if offset is None:
-        off += 1
-    else:
-        assert 1 <= offset
-        off = offset
-    if diskversion not in obsolete.formats:
-        raise error.Abort(_('parsing obsolete marker: unknown version %r')
-                          % diskversion)
-    return diskversion, obsolete.formats[diskversion][0](data, off)
+if obsolete._readmarkers.__code__.co_argcount > 1:
+    # hg-4.3+ has the "offset" parameter, and _fm?readmarkers also have an
+    # extra "stop" parameter
+    _readmarkers = obsolete._readmarkers
+else:
+    # XXX copied as is from Mercurial 4.2 and added the "offset" parameters
+    @util.nogc
+    def _readmarkers(data, offset=None):
+        """Read and enumerate markers from raw data"""
+        off = 0
+        diskversion = struct.unpack('>B', data[off:off + 1])[0]
+        if offset is None:
+            off += 1
+        else:
+            assert 1 <= offset
+            off = offset
+        if diskversion not in obsolete.formats:
+            raise error.Abort(_('parsing obsolete marker: unknown version %r')
+                              % diskversion)
+        return diskversion, obsolete.formats[diskversion][0](data, off)
 
 def markersfrom(obsstore, byteoffset, firstmarker):
     if not firstmarker:
--- a/hgext3rd/evolve/obshistory.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/obshistory.py	Wed Sep 27 01:12:47 2017 +0200
@@ -74,11 +74,8 @@
     if opts['graph']:
         return _debugobshistorygraph(ui, repo, revs, opts)
 
-    fm = ui.formatter('debugobshistory', opts)
     revs.reverse()
-    _debugobshistoryrevs(fm, repo, revs, opts)
-
-    fm.end()
+    _debugobshistoryrevs(ui, repo, revs, opts)
 
 class obsmarker_printer(cmdutil.changeset_printer):
     """show (available) information about a node
@@ -92,20 +89,23 @@
 
             changenode = ctx.node()
 
-            fm = self.ui.formatter('debugobshistory', props)
+            _props = self.diffopts.copy()
+            _props.update(props)
+            fm = self.ui.formatter('debugobshistory', _props)
             _debugobshistorydisplaynode(fm, self.repo, changenode)
 
             # Succs markers
             succs = self.repo.obsstore.successors.get(changenode, ())
             succs = sorted(succs)
 
-            markerfm = fm.nested("debugobshistory.markers")
+            markerfm = fm.nested("markers")
             for successor in succs:
                 _debugobshistorydisplaymarker(markerfm, successor,
                                               ctx.node(), self.repo, self.diffopts)
             markerfm.end()
 
             markerfm.plain('\n')
+            fm.end()
             self.hunk[ctx.node()] = self.ui.popbuffer()
         else:
             ### graph output is buffered only
@@ -301,7 +301,7 @@
     - The dictionnary of each node successors, values are a set
     - The dictionnary of each node precursors, values are a list
     """
-    precursors = repo.obsstore.precursors
+    precursors = repo.obsstore.predecessors
     successors = repo.obsstore.successors
     nodec = repo.changelog.node
 
@@ -355,10 +355,11 @@
     walker = _obshistorywalker(repo.unfiltered(), revs, opts.get('all', False))
     cmdutil.displaygraph(ui, repo, walker, displayer, edges)
 
-def _debugobshistoryrevs(fm, repo, revs, opts):
+def _debugobshistoryrevs(ui, repo, revs, opts):
     """ Display the obsolescence history for revset
     """
-    precursors = repo.obsstore.precursors
+    fm = ui.formatter('debugobshistory', opts)
+    precursors = repo.obsstore.predecessors
     successors = repo.obsstore.successors
     nodec = repo.changelog.node
     unfi = repo.unfiltered()
@@ -373,9 +374,9 @@
 
         succs = successors.get(ctxnode, ())
 
-        markerfm = fm.nested("debugobshistory.markers")
+        markerfm = fm.nested("markers")
         for successor in sorted(succs):
-            _debugobshistorydisplaymarker(markerfm, successor, ctxnode, repo, opts)
+            _debugobshistorydisplaymarker(markerfm, successor, ctxnode, unfi, opts)
         markerfm.end()
 
         precs = precursors.get(ctxnode, ())
@@ -384,6 +385,7 @@
             if p[0] not in seen:
                 seen.add(p[0])
                 nodes.append(p[0])
+    fm.end()
 
 def _debugobshistorydisplaynode(fm, repo, node):
     if node in repo:
@@ -395,22 +397,22 @@
     shortdescription = ctx.description().splitlines()[0]
 
     fm.startitem()
-    fm.write('debugobshistory.node', '%s', str(ctx),
+    fm.write('node', '%s', str(ctx),
              label="evolve.node")
     fm.plain(' ')
 
-    fm.write('debugobshistory.rev', '(%d)', int(ctx),
+    fm.write('rev', '(%d)', int(ctx),
              label="evolve.rev")
     fm.plain(' ')
 
-    fm.write('debugobshistory.shortdescription', '%s', shortdescription,
+    fm.write('shortdescription', '%s', shortdescription,
              label="evolve.short_description")
     fm.plain('\n')
 
 def _debugobshistorydisplaymissingctx(fm, nodewithoutctx):
     hexnode = nodemod.short(nodewithoutctx)
     fm.startitem()
-    fm.write('debugobshistory.node', '%s', hexnode,
+    fm.write('node', '%s', hexnode,
              label="evolve.node evolve.missing_change_ctx")
     fm.plain('\n')
 
@@ -428,7 +430,7 @@
     else:
         verb = 'rewritten'
 
-    fm.write('debugobshistory.verb', '%s', verb,
+    fm.write('verb', '%s', verb,
              label="evolve.verb")
 
     effectflag = metadata.get('ef1')
@@ -457,26 +459,26 @@
             effect.append('content')
 
         if effect:
-            fmteffect = fm.formatlist(effect, 'debugobshistory.effect', sep=', ')
-            fm.write('debugobshistory.effect', '(%s)', fmteffect)
-
-    fm.plain(' by ')
-
-    fm.write('debugobshistory.marker_user', '%s', metadata['user'],
-             label="evolve.user")
-    fm.plain(' ')
-
-    fm.write('debugobshistory.marker_date', '(%s)', fm.formatdate(date),
-             label="evolve.date")
+            fmteffect = fm.formatlist(effect, 'effect', sep=', ')
+            fm.write('effect', '(%s)', fmteffect)
 
     if len(succnodes) > 0:
         fm.plain(' as ')
 
         shortsnodes = (nodemod.short(succnode) for succnode in sorted(succnodes))
-        nodes = fm.formatlist(shortsnodes, 'debugobshistory.succnodes', sep=', ')
-        fm.write('debugobshistory.succnodes', '%s', nodes,
+        nodes = fm.formatlist(shortsnodes, 'succnodes', sep=', ')
+        fm.write('succnodes', '%s', nodes,
                  label="evolve.node")
 
+    fm.plain(' by ')
+
+    fm.write('user', '%s', metadata['user'],
+             label="evolve.user")
+    fm.plain(' ')
+
+    fm.write('date', '(%s)', fm.formatdate(date),
+             label="evolve.date")
+
     # Patch display
     if opts.get('patch'):
         _patchavailable = patchavailable(node, repo, marker)
@@ -726,13 +728,39 @@
 
     return {'users': sorted(users)}
 
+VERBMAPPING = {
+    DESCCHANGED: "reworded",
+    METACHANGED: "meta-changed",
+    USERCHANGED: "reauthored",
+    DATECHANGED: "date-changed",
+    BRANCHCHANGED: "branch-changed",
+    PARENTCHANGED: "rebased",
+    DIFFCHANGED: "amended"
+}
+
 def _successorsetverb(successorset, markers):
     """ Return the verb summarizing the successorset
     """
+    verb = None
     if not successorset:
         verb = 'pruned'
     elif len(successorset) == 1:
-        verb = 'rewritten'
+        # Check for effect flag
+
+        metadata = [dict(marker[3]) for marker in markers]
+        ef1 = [data.get('ef1') for data in metadata]
+
+        if all(ef1):
+            combined = 0
+            for ef in ef1:
+                combined |= int(ef)
+
+            # Combined will be in VERBMAPPING only of one bit is set
+            if combined in VERBMAPPING:
+                verb = VERBMAPPING[combined]
+
+        if verb is None:
+            verb = 'rewritten'
     else:
         verb = 'split'
     return {'verb': verb}
--- a/hgext3rd/evolve/templatekw.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/evolve/templatekw.py	Wed Sep 27 01:12:47 2017 +0200
@@ -28,7 +28,7 @@
 
 @eh.templatekw('obsolete')
 def obsoletekw(repo, ctx, templ, **args):
-    """:obsolete: String. Whether the changeset is ``obsolete``.
+    """String. Whether the changeset is ``obsolete``.
     """
     if ctx.obsolete():
         return 'obsolete'
@@ -36,22 +36,22 @@
 
 @eh.templatekw('troubles')
 def showtroubles(**args):
-    """:troubles: List of strings. Evolution troubles affecting the changeset
+    """List of strings. Evolution troubles affecting the changeset
     (zero or more of "unstable", "divergent" or "bumped")."""
     ctx = args['ctx']
     try:
         # specify plural= explicitly to trigger TypeError on hg < 4.2
-        return templatekw.showlist('trouble', ctx.troubles(), args,
+        return templatekw.showlist('trouble', ctx.instabilities(), args,
                                    plural='troubles')
     except TypeError:
-        return templatekw.showlist('trouble', ctx.troubles(), plural='troubles',
+        return templatekw.showlist('trouble', ctx.instabilities(), plural='troubles',
                                    **args)
 
 def closestprecursors(repo, nodeid):
     """ Yield the list of next precursors pointing on visible changectx nodes
     """
 
-    precursors = repo.obsstore.precursors
+    precursors = repo.obsstore.predecessors
     stack = [nodeid]
 
     while stack:
@@ -138,8 +138,8 @@
     # Assemble them
     return {
         'obsfate_quiet': verbtempl + succtempl,
-        'obsfate': verbtempl + optionalusertempl + succtempl,
-        'obsfate_verbose': verbtempl + usertempl + succtempl + datetempl,
+        'obsfate': verbtempl + succtempl + optionalusertempl,
+        'obsfate_verbose': verbtempl + succtempl + usertempl + datetempl,
     }
 
 def obsfatedata(repo, ctx):
--- a/hgext3rd/topic/__init__.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/topic/__init__.py	Wed Sep 27 01:12:47 2017 +0200
@@ -54,9 +54,12 @@
 
 import re
 import time
+import weakref
 
 from mercurial.i18n import _
 from mercurial import (
+    bookmarks,
+    changelog,
     cmdutil,
     commands,
     context,
@@ -64,20 +67,21 @@
     extensions,
     hg,
     localrepo,
-    lock,
+    lock as lockmod,
     merge,
     namespaces,
     node,
     obsolete,
-    obsutil,
     patch,
     phases,
     registrar,
+    scmutil,
     templatefilters,
     util,
 )
 
 from . import (
+    compat,
     constants,
     revset as topicrevset,
     destination,
@@ -118,7 +122,7 @@
               'topic.active': 'green',
              }
 
-version = '0.2.0'
+__version__ = '0.3.0.dev'
 testedwith = '4.0.2 4.1.3 4.2.1'
 minimumhgversion = '4.0'
 buglink = 'https://bz.mercurial-scm.org/'
@@ -134,7 +138,7 @@
         # 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)
+    revlist = stack.stack(self._repo, topic=topic)
     try:
         return revlist.index(self.rev())
     except IndexError:
@@ -153,12 +157,12 @@
         tname = topic = repo.currenttopic
         if not tname:
             raise error.Abort(_('cannot resolve "%s": no active topic') % name)
-        revs = list(stack.getstack(repo, topic=topic))
+        revs = list(stack.stack(repo, topic=topic))
     elif branchrev.match(name):
         ttype = 'branch'
         idx = int(name[1:])
         tname = branch = repo[None].branch()
-        revs = list(stack.getstack(repo, branch=branch))
+        revs = list(stack.stack(repo, branch=branch))
 
     if revs is not None:
         try:
@@ -185,7 +189,6 @@
 
 def uisetup(ui):
     destination.modsetup(ui)
-    topicrevset.modsetup(ui)
     discovery.modsetup(ui)
     topicmap.modsetup(ui)
     setupimportexport(ui)
@@ -196,6 +199,15 @@
     entry[1].append(('t', 'topic', '',
                      _("use specified topic"), _('TOPIC')))
 
+    entry = extensions.wrapcommand(commands.table, 'push', pushoutgoingwrap)
+    entry[1].append(('t', 'topic', '',
+                     _("topic to push"), _('TOPIC')))
+
+    entry = extensions.wrapcommand(commands.table, 'outgoing',
+                                   pushoutgoingwrap)
+    entry[1].append(('t', 'topic', '',
+                     _("topic to push"), _('TOPIC')))
+
     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
@@ -300,44 +312,139 @@
                 peer.__class__ = topicpeer
             return peer
 
+        def transaction(self, desc, *a, **k):
+            ctr = self.currenttransaction()
+            tr = super(topicrepo, self).transaction(desc, *a, **k)
+            if desc in ('strip', 'repair') or ctr is not None:
+                return tr
+
+            # real transaction start
+            ct = self.currenttopic
+            if not ct:
+                return tr
+            ctwasempty = stack.stackdata(self, topic=ct)['changesetcount'] == 0
+
+            reporef = weakref.ref(self)
+
+            def currenttopicempty(tr):
+                # check active topic emptyness
+                repo = reporef()
+                csetcount = stack.stackdata(repo, topic=ct)['changesetcount']
+                empty = csetcount == 0
+                if empty and not ctwasempty:
+                    ui.status('active topic %r is now empty\n' % ct)
+                if ctwasempty and not empty:
+                    if csetcount == 1:
+                        msg = _('active topic %r grew its first changeset\n')
+                        ui.status(msg % ct)
+                    else:
+                        msg = _('active topic %r grew its %s first changesets\n')
+                        ui.status(msg % (ct, csetcount))
+
+            tr.addpostclose('signalcurrenttopicempty', currenttopicempty)
+            return tr
+
     repo.__class__ = topicrepo
     repo._topics = None
     if util.safehasattr(repo, 'names'):
         repo.names.addnamespace(namespaces.namespace(
             'topics', 'topic', namemap=_namemap, nodemap=_nodemap,
             listnames=lambda repo: repo.topics))
+    # Wrap workingctx extra to return the topic name
+    extensions.wrapfunction(context.workingctx, '__init__', wrapinit)
+    # Wrap changelog.add to drop empty topic
+    extensions.wrapfunction(changelog.changelog, 'add', wrapadd)
+
+def wrapinit(orig, self, repo, *args, **kwargs):
+    orig(self, repo, *args, **kwargs)
+    if repo.currenttopic:
+        self._extra[constants.extrakey] = repo.currenttopic
+    else:
+        # Empty key will be dropped from extra by another hack at the changegroup level
+        self._extra[constants.extrakey] = ''
+
+def wrapadd(orig, cl, manifest, files, desc, transaction, p1, p2, user,
+            date=None, extra=None):
+    if constants.extrakey in extra and not extra[constants.extrakey]:
+        extra = extra.copy()
+        del extra[constants.extrakey]
+    return orig(cl, manifest, files, desc, transaction, p1, p2, user,
+                date=date, extra=extra)
+
+# revset predicates are automatically registered at loading via this symbol
+revsetpredicate = topicrevset.revsetpredicate
 
 @command('topics', [
         ('', 'clear', False, 'clear active topic if any'),
-        ('r', 'rev', '', 'revset of existing revisions', _('REV')),
+        ('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')
+        ('', 'age', False, 'show when you last touched the topics'),
+        ('', 'current', None, 'display the current topic only'),
     ] + commands.formatteropts,
     _('hg topics [TOPIC]'))
-def topics(ui, repo, topic='', clear=False, rev=None, list=False, **opts):
+def topics(ui, repo, topic=None, **opts):
     """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`
+    Clear topic on existing topiced revisions::
+
+      hg topics --rev <related revset> --clear
+
+    Change topic on some revisions::
 
-    Change topic on some revisions:
-        `hg topic <newtopicname> --rev <related revset>`
+      hg topics <newtopicname> --rev <related revset>
 
-    Clear current topic:
-        `hg topic --clear`
+    Clear current topic::
+
+      hg topics --clear
 
-    Set current topic:
-        `hg topic <topicname>`
+    Set current topic::
+
+      hg topics <topicname>
+
+    List of topics::
 
-    List of topics:
-        `hg topics`
+      hg topics
 
-    List of topics with their last touched time sorted according to it:
-        `hg topic --age`
+    List of topics sorted according to their last touched time displaying last
+    touched time and the user who last touched the topic::
+
+      hg topics --age
 
     The active topic (if any) will be prepended with a "*".
 
+    The `--current` flag helps to take active topic into account. For
+    example, if you want to set the topic on all the draft changesets to the
+    active topic, you can do:
+        `hg topics -r "draft()" --current`
+
     The --verbose version of this command display various information on the state of each topic."""
+
+    clear = opts.get('clear')
+    list = opts.get('list')
+    rev = opts.get('rev')
+    current = opts.get('current')
+    age = opts.get('age')
+
+    if current and topic:
+        raise error.Abort(_("cannot use --current when setting a topic"))
+    if current and clear:
+        raise error.Abort(_("cannot use --current and --clear"))
+    if clear and topic:
+        raise error.Abort(_("cannot use --clear when setting a topic"))
+    if age and topic:
+        raise error.Abort(_("cannot use --age while setting a topic"))
+
+    touchedrevs = set()
+    if rev:
+        touchedrevs = scmutil.revrange(repo, rev)
+
+    if topic:
+        topic = topic.strip()
+        if not topic:
+            raise error.Abort(_("topic name cannot consist entirely of whitespaces"))
+        # Have some restrictions on the topic name just like bookmark name
+        scmutil.checknewlabel(repo, topic, 'topic')
+
     if list:
         if clear or rev:
             raise error.Abort(_("cannot use --clear or --rev with --list"))
@@ -347,24 +454,58 @@
             raise error.Abort(_('no active topic to list'))
         return stack.showstack(ui, repo, topic=topic, opts=opts)
 
-    if rev:
+    if touchedrevs:
         if not obsolete.isenabled(repo, obsolete.createmarkersopt):
             raise error.Abort(_('must have obsolete enabled to change topics'))
         if clear:
             topic = None
+        elif opts.get('current'):
+            topic = repo.currenttopic
         elif not topic:
             raise error.Abort('changing topic requires a topic name or --clear')
-        if any(not c.mutable() for c in repo.set('%r and public()', rev)):
+        if repo.revs('%ld and public()', touchedrevs):
             raise error.Abort("can't change topic of a public change")
-        return _changetopics(ui, repo, rev, topic)
+        wl = l = txn = None
+        try:
+            wl = repo.wlock()
+            l = repo.lock()
+            txn = repo.transaction('rewrite-topics')
+            rewrote = _changetopics(ui, repo, touchedrevs, topic)
+            txn.close()
+            ui.status('changed topic on %d changes\n' % rewrote)
+        finally:
+            lockmod.release(txn, l, wl)
+            repo.invalidate()
+        return
 
+    ct = repo.currenttopic
     if clear:
+        empty = stack.stackdata(repo, topic=ct)['changesetcount'] == 0
+        if empty:
+            if ct:
+                ui.status(_('clearing empty topic "%s"\n') % ct)
         return _changecurrenttopic(repo, None)
 
     if topic:
+        if not ct:
+            ui.status(_('marked working directory as topic: %s\n') % topic)
         return _changecurrenttopic(repo, topic)
 
-    _listtopics(ui, repo, opts)
+    # `hg topic --current`
+    ret = 0
+    if current and not ct:
+        ui.write_err(_('no active topic\n'))
+        ret = 1
+    elif current:
+        fm = ui.formatter('topic', opts)
+        namemask = '%s\n'
+        label = 'topic.active'
+        fm.startitem()
+        fm.write('topic', namemask, ct, label=label)
+        fm.end()
+    else:
+        _listtopics(ui, repo, opts)
+    return ret
 
 @command('stack', [
     ] + commands.formatteropts,
@@ -385,6 +526,128 @@
         branch = repo[None].branch()
     return stack.showstack(ui, repo, branch=branch, topic=topic, opts=opts)
 
+@command('debugcb|debugconvertbookmark', [
+        ('b', 'bookmark', '', _('bookmark to convert to topic')),
+        ('', 'all', None, _('convert all bookmarks to topics')),
+    ],
+    _('[-b BOOKMARK] [--all]'))
+def debugconvertbookmark(ui, repo, **opts):
+    """Converts a bookmark to a topic with the same name.
+    """
+
+    bookmark = opts.get('bookmark')
+    convertall = opts.get('all')
+
+    if convertall and bookmark:
+        raise error.Abort(_("cannot use '--all' and '-b' together"))
+    if not (convertall or bookmark):
+        raise error.Abort(_("you must specify either '--all' or '-b'"))
+
+    bmstore = repo._bookmarks
+
+    nodetobook = {}
+    for book, revnode in bmstore.iteritems():
+        if nodetobook.get(revnode):
+            nodetobook[revnode].append(book)
+        else:
+            nodetobook[revnode] = [book]
+
+    # a list of nodes which we have skipped so that we don't print the skip
+    # warning repeatedly
+    skipped = []
+
+    actions = {}
+
+    lock = wlock = tr = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+        if bookmark:
+            try:
+                node = bmstore[bookmark]
+            except KeyError:
+                raise error.Abort(_("no such bookmark exists: '%s'") % bookmark)
+
+            revnum = repo[node].rev()
+            if len(nodetobook[node]) > 1:
+                ui.status(_("skipping revision '%d' as it has multiple bookmarks "
+                          "on it\n") % revnum)
+                return
+            targetrevs = _findconvertbmarktopic(repo, bookmark)
+            if targetrevs:
+                actions[(bookmark, revnum)] = targetrevs
+
+        elif convertall:
+            for bmark, revnode in sorted(bmstore.iteritems()):
+                revnum = repo[revnode].rev()
+                if revnum in skipped:
+                    continue
+                if len(nodetobook[revnode]) > 1:
+                    ui.status(_("skipping '%d' as it has multiple bookmarks on"
+                              " it\n") % revnum)
+                    skipped.append(revnum)
+                    continue
+                if bmark == '@':
+                    continue
+                targetrevs = _findconvertbmarktopic(repo, bmark)
+                if targetrevs:
+                    actions[(bmark, revnum)] = targetrevs
+
+        if actions:
+            try:
+                tr = repo.transaction('debugconvertbookmark')
+                for ((bmark, revnum), targetrevs) in sorted(actions.iteritems()):
+                    _applyconvertbmarktopic(ui, repo, targetrevs, revnum, bmark, tr)
+                tr.close()
+            finally:
+                tr.release()
+    finally:
+        lockmod.release(lock, wlock)
+
+# inspired from mercurial.repair.stripbmrevset
+CONVERTBOOKREVSET = """
+not public() and (
+    ancestors(bookmark(%s))
+    and not ancestors(
+        (
+            (head() and not bookmark(%s))
+            or (bookmark() - bookmark(%s))
+        ) - (
+            descendants(bookmark(%s))
+            - bookmark(%s)
+        )
+    )
+)
+"""
+
+def _findconvertbmarktopic(repo, bmark):
+    """find revisions unambigiously defined by a bookmark
+
+    find all changesets under the bookmark and under that bookmark only.
+    """
+    return repo.revs(CONVERTBOOKREVSET, bmark, bmark, bmark, bmark, bmark)
+
+def _applyconvertbmarktopic(ui, repo, revs, old, bmark, tr):
+    """apply bookmark convertion to topic
+
+    Sets a topic as same as bname to all the changesets under the bookmark
+    and delete the bookmark, if topic is set to any changeset
+
+    old is the revision on which bookmark bmark is and tr is transaction object.
+    """
+
+    rewrote = _changetopics(ui, repo, revs, bmark)
+    # We didn't changed topic to any changesets because the revset
+    # returned an empty set of revisions, so let's skip deleting the
+    # bookmark corresponding to which we didn't put a topic on any
+    # changeset
+    if rewrote == 0:
+        return
+    ui.status(_('changed topic to "%s" on %d revisions\n') % (bmark,
+              rewrote))
+    ui.debug('removing bookmark "%s" from "%d"' % (bmark, old))
+    bookmarks.delete(repo, tr, [bmark])
+
 def _changecurrenttopic(repo, newtopic):
     """changes the current topic."""
 
@@ -396,73 +659,69 @@
         if repo.vfs.exists('topic'):
             repo.vfs.unlink('topic')
 
-def _changetopics(ui, repo, revset, newtopic):
+def _changetopics(ui, repo, revs, newtopic):
+    """ Changes topic to newtopic of all the revisions in the revset and return
+    the count of revisions whose topic has been changed.
+    """
     rewrote = 0
-    wl = l = txn = None
-    try:
-        wl = repo.wlock()
-        l = repo.lock()
-        txn = repo.transaction('rewrite-topics')
-        p1 = None
-        p2 = None
-        successors = {}
-        for c in repo.set('%r', revset):
-            def filectxfn(repo, ctx, path):
-                try:
-                    return c[path]
-                except error.ManifestLookupError:
-                    return None
-            fixedextra = dict(c.extra())
-            ui.debug('old node id is %s\n' % node.hex(c.node()))
-            ui.debug('origextra: %r\n' % fixedextra)
-            oldtopic = fixedextra.get(constants.extrakey, None)
-            if oldtopic == newtopic:
-                continue
-            if newtopic is None:
-                del fixedextra[constants.extrakey]
-            else:
-                fixedextra[constants.extrakey] = newtopic
-            fixedextra[constants.changekey] = c.hex()
-            if 'amend_source' in fixedextra:
-                # TODO: right now the commitctx wrapper in
-                # topicrepo overwrites the topic in extra if
-                # amend_source is set to support 'hg commit
-                # --amend'. Support for amend should be adjusted
-                # to not be so invasive.
-                del fixedextra['amend_source']
-            ui.debug('changing topic of %s from %s to %s\n' % (
-                c, oldtopic, newtopic))
-            ui.debug('fixedextra: %r\n' % fixedextra)
-            # While changing topic of set of linear commits, make sure that
-            # we base our commits on new parent rather than old parent which
-            # was obsoleted while changing the topic
-            p1 = c.p1().node()
-            p2 = c.p2().node()
-            if p1 in successors:
-                p1 = successors[p1]
-            if p2 in successors:
-                p2 = successors[p2]
-            mc = context.memctx(
-                repo, (p1, p2), c.description(),
-                c.files(), filectxfn,
-                user=c.user(), date=c.date(), extra=fixedextra)
-            newnode = repo.commitctx(mc)
-            successors[c.node()] = newnode
-            ui.debug('new node id is %s\n' % node.hex(newnode))
-            obsolete.createmarkers(repo, [(c, (repo[newnode],))])
-            rewrote += 1
-        # move the working copy too
-        wctx = repo[None]
-        # in-progress merge is a bit too complex for now.
-        if len(wctx.parents()) == 1:
-            newid = successors.get(wctx.p1().node())
-            if newid is not None:
-                hg.update(repo, newid, quietempty=True)
-        txn.close()
-    finally:
-        lock.release(txn, l, wl)
-        repo.invalidate()
-    ui.status('changed topic on %d changes\n' % rewrote)
+    p1 = None
+    p2 = None
+    successors = {}
+    for r in revs:
+        c = repo[r]
+
+        def filectxfn(repo, ctx, path):
+            try:
+                return c[path]
+            except error.ManifestLookupError:
+                return None
+        fixedextra = dict(c.extra())
+        ui.debug('old node id is %s\n' % node.hex(c.node()))
+        ui.debug('origextra: %r\n' % fixedextra)
+        oldtopic = fixedextra.get(constants.extrakey, None)
+        if oldtopic == newtopic:
+            continue
+        if newtopic is None:
+            del fixedextra[constants.extrakey]
+        else:
+            fixedextra[constants.extrakey] = newtopic
+        fixedextra[constants.changekey] = c.hex()
+        if 'amend_source' in fixedextra:
+            # TODO: right now the commitctx wrapper in
+            # topicrepo overwrites the topic in extra if
+            # amend_source is set to support 'hg commit
+            # --amend'. Support for amend should be adjusted
+            # to not be so invasive.
+            del fixedextra['amend_source']
+        ui.debug('changing topic of %s from %s to %s\n' % (
+            c, oldtopic, newtopic))
+        ui.debug('fixedextra: %r\n' % fixedextra)
+        # While changing topic of set of linear commits, make sure that
+        # we base our commits on new parent rather than old parent which
+        # was obsoleted while changing the topic
+        p1 = c.p1().node()
+        p2 = c.p2().node()
+        if p1 in successors:
+            p1 = successors[p1]
+        if p2 in successors:
+            p2 = successors[p2]
+        mc = context.memctx(
+            repo, (p1, p2), c.description(),
+            c.files(), filectxfn,
+            user=c.user(), date=c.date(), extra=fixedextra)
+        newnode = repo.commitctx(mc)
+        successors[c.node()] = newnode
+        ui.debug('new node id is %s\n' % node.hex(newnode))
+        obsolete.createmarkers(repo, [(c, (repo[newnode],))])
+        rewrote += 1
+    # move the working copy too
+    wctx = repo[None]
+    # in-progress merge is a bit too complex for now.
+    if len(wctx.parents()) == 1:
+        newid = successors.get(wctx.p1().node())
+        if newid is not None:
+            hg.update(repo, newid, quietempty=True)
+    return rewrote
 
 def _listtopics(ui, repo, opts):
     fm = ui.formatter('topics', opts)
@@ -517,7 +776,7 @@
             elif -1 == data['behindcount']:
                 fm.plain(', ')
                 fm.write('behinderror', '%s',
-                         _('ambiguous destination'),
+                         _('ambiguous destination: %s') % data['behinderror'],
                          label='topic.list.behinderror')
             fm.plain(')')
         fm.plain('\n')
@@ -533,8 +792,8 @@
         namemask = '%%-%is' % maxwidth
     activetopic = repo.currenttopic
     for timevalue in times:
-        curtopics = timedict[timevalue][1]
-        for topic in curtopics:
+        curtopics = sorted(timedict[timevalue][1])
+        for topic, user in curtopics:
             fm.startitem()
             marker = ' '
             label = 'topic'
@@ -547,10 +806,12 @@
             fm.data(active=active)
             fm.plain(' (')
             if timevalue == -1:
-                timestr = 'not yet touched'
+                timestr = 'empty and active'
             else:
                 timestr = templatefilters.age(timedict[timevalue][0])
             fm.write('lasttouched', '%s', timestr, label='topic.list.time')
+            if user:
+                fm.write('usertouched', ' by %s', user, label='topic.list.user')
             fm.plain(')')
             fm.plain('\n')
     fm.end()
@@ -563,6 +824,8 @@
     topicstime = {}
     curtime = time.time()
     for t in topics:
+        secspassed = -1
+        user = None
         maxtime = (0, 0)
         trevs = repo.revs("topic(%s)", t)
         # Need to check for the time of all changesets in the topic, whether
@@ -570,26 +833,38 @@
         # 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]:
+            if rt[0] >= maxtime[0]:
                 # Can store the rev to gather more info
                 # latesthead = revs
                 maxtime = rt
+                user = repo[revs].user()
             # looking on the markers also to get more information and accurate
             # last touch time.
-            obsmarkers = obsutil.getmarkers(repo, [repo[revs].node()])
+            obsmarkers = compat.getmarkers(repo, [repo[revs].node()])
             for marker in obsmarkers:
                 rt = marker.date()
                 if rt[0] > maxtime[0]:
+                    user = marker.metadata().get('user', user)
                     maxtime = rt
-        # is the topic still yet untouched
-        if not trevs:
-            secspassed = -1
-        else:
+
+        # Making the username more better
+        username = None
+        if user:
+            # user is of form "abc <abc@xyz.com>"
+            username = user.split('<')[0]
+            if not username:
+                # user is of form "<abc@xyz.com>"
+                username = user[1:-1]
+            username = username.strip()
+
+        topicuser = (t, username)
+
+        if trevs:
             secspassed = (curtime - maxtime[0])
         try:
-            topicstime[secspassed][1].append(t)
+            topicstime[secspassed][1].append(topicuser)
         except KeyError:
-            topicstime[secspassed] = (maxtime, [t])
+            topicstime[secspassed] = (maxtime, [topicuser])
 
     return topicstime
 
@@ -622,6 +897,12 @@
                           "\nHG: topic '%s'\nHG: branch" % t)
     return ret
 
+def pushoutgoingwrap(orig, ui, repo, *args, **opts):
+    if opts.get('topic'):
+        topicrevs = repo.revs('topic(%s) - obsolete()', opts['topic'])
+        opts.setdefault('rev', []).extend(topicrevs)
+    return orig(ui, repo, *args, **opts)
+
 def mergeupdatewrap(orig, repo, node, branchmerge, force, *args, **kwargs):
     matcher = kwargs.get('matcher')
     partial = not (matcher is None or matcher.always())
@@ -635,12 +916,13 @@
         # if rebase is running and update the currenttopic to topic of new
         # rebased commit. We have explicitly stored in config if rebase is
         # running.
+        ot = repo.currenttopic
+        empty = stack.stackdata(repo, topic=ot)['changesetcount'] == 0
         if repo.ui.hasconfig('experimental', 'topicrebase'):
             isrebase = True
         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]
             if pctx.phase() > phases.public:
@@ -649,9 +931,10 @@
                 f.write(t)
             if t and t != ot:
                 repo.ui.status(_("switching to topic %s\n") % t)
+            if ot and not t and empty:
+                repo.ui.status(_('clearing empty topic "%s"\n') % ot)
         elif ist0:
-            repo.ui.status(_("preserving the current topic '%s'\n") %
-                           repo.currenttopic)
+            repo.ui.status(_("preserving the current topic '%s'\n") % ot)
         return ret
     finally:
         wlock.release()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext3rd/topic/compat.py	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,24 @@
+# Copyright 2017 FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""
+Compatibility module
+"""
+from __future__ import absolute_import
+
+from mercurial import obsolete
+
+getmarkers = None
+successorssets = None
+try:
+    from mercurial import obsutil
+    getmarkers = getattr(obsutil, 'getmarkers', None)
+    successorssets = getattr(obsutil, 'successorssets', None)
+except ImportError:
+    pass
+
+if getmarkers is None:
+    getmarkers = obsolete.getmarkers
+if successorssets is None:
+    successorssets = obsolete.successorssets
--- a/hgext3rd/topic/destination.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/topic/destination.py	Wed Sep 27 01:12:47 2017 +0200
@@ -106,9 +106,14 @@
         rebase = extensions.find('rebase')
     except KeyError:
         rebase = None
+
+    # Mercurial 4.4 rename _definesets into _definedestmap
+    rebasebefore38 = not util.safehasattr(rebase, '_definesets')
+    rebasebefore44 = not util.safehasattr(rebase, '_definedestmap')
+
     if (util.safehasattr(rebase, '_destrebase')
             # logic not shared with merge yet < hg-3.8
-            and not util.safehasattr(rebase, '_definesets')):
+            and rebasebefore38 and rebasebefore44):
         extensions.wrapfunction(rebase, '_destrebase', _destmergebranch)
     if util.safehasattr(destutil, 'destupdatesteps'):
         bridx = destutil.destupdatesteps.index('branch')
--- a/hgext3rd/topic/evolvebits.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/topic/evolvebits.py	Wed Sep 27 01:12:47 2017 +0200
@@ -1,15 +1,6 @@
 import collections
-from mercurial import obsolete
 
-successorssets = None
-try:
-    from mercurial import obsutil
-    successorssets = getattr(obsutil, 'successorssets', None)
-except ImportError:
-    pass
-
-if successorssets is None:
-    successorssets = obsolete.successorssets
+from . import compat
 
 # Copied from evolve 081605c2e9b6
 
@@ -82,14 +73,14 @@
         return p.rev()
     obs = repo[p]
     ui = repo.ui
-    newer = successorssets(repo, obs.node())
+    newer = compat.successorssets(repo, obs.node())
     # search of a parent which is not killed
     while not newer:
         ui.debug("stabilize target %s is plain dead,"
                  " trying to stabilize on its parent\n" %
                  obs)
         obs = obs.parents()[0]
-        newer = successorssets(repo, obs.node())
+        newer = compat.successorssets(repo, obs.node())
     if len(newer) > 1 or len(newer[0]) > 1:
         raise MultipleSuccessorsError(newer)
 
--- a/hgext3rd/topic/revset.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/topic/revset.py	Wed Sep 27 01:12:47 2017 +0200
@@ -1,6 +1,7 @@
 from __future__ import absolute_import
 
 from mercurial import (
+    registrar,
     revset,
     util,
 )
@@ -16,10 +17,11 @@
 except AttributeError:
     mkmatcher = util.stringmatcher
 
+revsetpredicate = registrar.revsetpredicate()
 
+@revsetpredicate('topic([topic])')
 def topicset(repo, subset, x):
-    """`topic([topic])`
-    Specified topic or all changes with any topic specified.
+    """Specified topic or all changes with any topic specified.
 
     If `topic` starts with `re:` the remainder of the name is treated
     as a regular expression.
@@ -48,10 +50,9 @@
         return matcher(topic)
     return (subset & mutable).filter(matchtopic)
 
+@revsetpredicate('ngtip([branch])')
 def ngtipset(repo, subset, x):
-    """`ngtip([branch])`
-
-    The untopiced tip.
+    """The untopiced tip.
 
     Name is horrible so that people change it.
     """
@@ -62,9 +63,9 @@
         branch = repo['.'].branch()
     return subset & revset.baseset(destination.ngtip(repo, branch))
 
+@revsetpredicate('stack()')
 def stackset(repo, subset, x):
-    """`stack()`
-    All relevant changes in the current topic,
+    """All relevant changes in the current topic,
 
     This is roughly equivalent to 'topic(.) - obsolete' with a sorting moving
     unstable changeset after there future parent (as if evolve where already
@@ -78,10 +79,4 @@
         topic = repo.currenttopic
     if not topic:
         branch = repo[None].branch()
-    return revset.baseset(stack.getstack(repo, branch=branch, topic=topic)[1:]) & subset
-
-
-def modsetup(ui):
-    revset.symbols.update({'topic': topicset})
-    revset.symbols.update({'ngtip': ngtipset})
-    revset.symbols.update({'stack': stackset})
+    return revset.baseset(stack.stack(repo, branch=branch, topic=topic)[1:]) & subset
--- a/hgext3rd/topic/stack.py	Tue Jul 25 15:17:42 2017 +0200
+++ b/hgext3rd/topic/stack.py	Wed Sep 27 01:12:47 2017 +0200
@@ -5,30 +5,180 @@
 from mercurial.i18n import _
 from mercurial import (
     destutil,
+    context,
     error,
     node,
+    phases,
+    util,
 )
-from .evolvebits import builddependencies, _orderrevs, _singlesuccessor
+from .evolvebits import builddependencies, _singlesuccessor
 
 short = node.short
 
-def getstack(repo, branch=None, topic=None):
-    # XXX need sorting
-    if topic is not None and branch is not None:
-        raise error.ProgrammingError('both branch and topic specified (not defined yet)')
-    elif topic is not None:
-        trevs = repo.revs("topic(%s) - obsolete()", topic)
-    elif branch is not None:
-        trevs = repo.revs("branch(%s) - public() - obsolete() - topic()", branch)
-    else:
-        raise error.ProgrammingError('neither branch and topic specified (not defined yet)')
-    revs = _orderrevs(repo, trevs)
-    if revs:
-        pt1 = repo[revs[0]].p1()
+# TODO: compat
+
+if not util.safehasattr(context.basectx, 'orphan'):
+    context.basectx.orphan = context.basectx.unstable
+
+if not util.safehasattr(context.basectx, 'isunstable'):
+    context.basectx.isunstable = context.basectx.troubled
+
+class stack(object):
+    """object represent a stack and common logic associated to it."""
+
+    def __init__(self, repo, branch=None, topic=None):
+        self._repo = repo
+        self.branch = branch
+        self.topic = topic
+        self.behinderror = None
+        if topic is not None and branch is not None:
+            raise error.ProgrammingError('both branch and topic specified (not defined yet)')
+        elif topic is not None:
+            trevs = repo.revs("topic(%s) - obsolete()", topic)
+        elif branch is not None:
+            trevs = repo.revs("branch(%s) - public() - obsolete() - topic()", branch)
+        else:
+            raise error.ProgrammingError('neither branch and topic specified (not defined yet)')
+        self._revs = trevs
+
+    def __iter__(self):
+        return iter(self.revs)
+
+    def __getitem__(self, index):
+        return self.revs[index]
+
+    def index(self, item):
+        return self.revs.index(item)
+
+    @util.propertycache
+    def _dependencies(self):
+        deps, rdeps = builddependencies(self._repo, self._revs)
+
+        repo = self._repo
+        srcpfunc = repo.changelog.parentrevs
+
+        ### post process to skip over possible gaps in the stack
+        #
+        # For example in the following situation, we need to detect that "t3"
+        # indirectly depends on t2.
+        #
+        #  o t3
+        #  |
+        #  o other
+        #  |
+        #  o t2
+        #  |
+        #  o t1
+
+        pmap = {}
+
+        def pfuncrev(repo, rev):
+            """a special "parent func" that also consider successors"""
+            parents = pmap.get(rev)
+            if parents is None:
+                parents = [repo[_singlesuccessor(repo, repo[p])].rev()
+                           for p in srcpfunc(rev) if 0 <= p]
+                pmap[rev] = parents
+            return parents
+
+        revs = self._revs
+        stackrevs = set(self._revs)
+        for root in [r for r in revs if not deps[r]]:
+            seen = set()
+            stack = [root]
+            while stack:
+                current = stack.pop()
+                for p in pfuncrev(repo, current):
+                    if p in seen:
+                        continue
+                    seen.add(p)
+                    if p in stackrevs:
+                        rdeps[p].add(root)
+                        deps[root].add(p)
+                    elif phases.public < repo[p].phase():
+                        # traverse only if we did not found a proper candidate
+                        stack.append(p)
+
+        return deps, rdeps
+
+    @util.propertycache
+    def revs(self):
+        # some duplication/change from _orderrevs because we use a post
+        # processed dependency graph.
+
+        # Step 1: compute relation of revision with each other
+        dependencies, rdependencies = self._dependencies
+        dependencies = dependencies.copy()
+        rdependencies = rdependencies.copy()
+        # Step 2: Build the ordering
+        # Remove the revisions with no dependency(A) and add them to the ordering.
+        # Removing these revisions leads to new revisions with no dependency (the
+        # one depending on A) that we can remove from the dependency graph and add
+        # to the ordering. We progress in a similar fashion until the ordering is
+        # built
+        solvablerevs = [r for r in sorted(dependencies.keys())
+                        if not dependencies[r]]
+        revs = []
+        while solvablerevs:
+            rev = solvablerevs.pop()
+            for dependent in rdependencies[rev]:
+                dependencies[dependent].remove(rev)
+                if not dependencies[dependent]:
+                    solvablerevs.append(dependent)
+            del dependencies[rev]
+            revs.append(rev)
+
+        revs.extend(sorted(dependencies))
+        # step 3: add t0
+        if revs:
+            pt1 = self._repo[revs[0]].p1()
+        else:
+            pt1 = self._repo['.']
+
         if pt1.obsolete():
-            pt1 = repo[_singlesuccessor(repo, pt1)]
+            pt1 = self._repo[_singlesuccessor(self._repo, pt1)]
         revs.insert(0, pt1.rev())
-    return revs
+        return revs
+
+    @util.propertycache
+    def changesetcount(self):
+        return len(self._revs)
+
+    @util.propertycache
+    def troubledcount(self):
+        return len([r for r in self._revs if self._repo[r].isunstable()])
+
+    @util.propertycache
+    def heads(self):
+        revs = self.revs[1:]
+        deps, rdeps = self._dependencies
+        return [r for r in revs if not rdeps[r]]
+
+    @util.propertycache
+    def behindcount(self):
+        revs = self.revs[1:]
+        deps, rdeps = self._dependencies
+        if revs:
+            minroot = [min(r for r in revs if not deps[r])]
+            try:
+                dest = destutil.destmerge(self._repo, action='rebase',
+                                          sourceset=minroot,
+                                          onheadcheck=False)
+                return len(self._repo.revs("only(%d, %ld)", dest, minroot))
+            except error.NoMergeDestAbort:
+                return 0
+            except error.ManyMergeDestAbort as exc:
+                # XXX we should make it easier for upstream to provide the information
+                self.behinderror = str(exc).split('-', 1)[0].rstrip()
+                return -1
+        return 0
+
+    @util.propertycache
+    def branches(self):
+        branches = sorted(set(self._repo[r].branch() for r in self._revs))
+        if not branches:
+            branches = set([self._repo[None].branch()])
+        return branches
 
 def labelsgen(prefix, labelssuffix):
     """ Takes a label prefix and a list of suffixes. Returns a string of the prefix
@@ -63,6 +213,9 @@
         label = 'topic.active'
 
     data = stackdata(repo, branch=branch, topic=topic)
+    empty = False
+    if data['changesetcount'] == 0:
+        empty = True
     if topic is not None:
         fm.plain(_('### topic: %s')
                  % ui.label(topic, label),
@@ -74,7 +227,7 @@
                      label='topic.stack.summary.headcount.multiple')
             fm.plain(')')
         fm.plain('\n')
-    fm.plain(_('### branch: %s')
+    fm.plain(_('### target: %s (branch)')
              % '+'.join(data['branches']), # XXX handle multi branches
              label='topic.stack.summary.branches')
     if topic is None:
@@ -86,13 +239,17 @@
     else:
         if data['behindcount'] == -1:
             fm.plain(', ')
-            fm.plain('ambigious rebase destination', label='topic.stack.summary.behinderror')
+            fm.plain('ambigious rebase destination - %s' % data['behinderror'],
+                     label='topic.stack.summary.behinderror')
         elif data['behindcount']:
             fm.plain(', ')
             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), 0):
+    if empty:
+        fm.plain(_("(stack is empty)\n"))
+
+    for idx, r in enumerate(stack(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:
@@ -103,9 +260,13 @@
             prev = ctx.rev()
             continue
         p1 = ctx.p1()
+        p2 = ctx.p2()
         if p1.obsolete():
             p1 = repo[_singlesuccessor(repo, p1)]
-        if p1.rev() != prev and p1.node() != node.nullid:
+        if p2.node() != node.nullid:
+            entries.append((idxmap.get(p1.rev()), False, p1))
+            entries.append((idxmap.get(p2.rev()), False, p2))
+        elif p1.rev() != prev and p1.node() != node.nullid:
             entries.append((idxmap.get(p1.rev()), False, p1))
         entries.append((idx, True, ctx))
         idxmap[ctx.rev()] = idx
@@ -122,7 +283,7 @@
             # "base" is kind of a "ghost" entry
             # skip other label for them (no current, no unstable)
             states = ['base']
-        elif ctx.unstable():
+        elif ctx.orphan():
             # current revision can be unstable also, so in that case show both
             # the states and the symbol '@' (issue5553)
             if iscurrentrevision:
@@ -169,24 +330,11 @@
     :behindcount: number of changeset on rebase destination
     """
     data = {}
-    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)
-    data['headcount'] = len([r for r in revs if not rdeps[r]])
-    data['behindcount'] = 0
-    if revs:
-        minroot = [min(r for r in revs if not deps[r])]
-        try:
-            dest = destutil.destmerge(repo, action='rebase',
-                                      sourceset=minroot,
-                                      onheadcheck=False)
-            data['behindcount'] = len(repo.revs("only(%d, %ld)", dest,
-                                                minroot))
-        except error.NoMergeDestAbort:
-            data['behindcount'] = 0
-        except error.ManyMergeDestAbort:
-            data['behindcount'] = -1
-    data['branches'] = sorted(set(repo[r].branch() for r in revs))
-
+    current = stack(repo, branch, topic)
+    data['changesetcount'] = current.changesetcount
+    data['troubledcount'] = current.troubledcount
+    data['headcount'] = len(current.heads)
+    data['behindcount'] = current.behindcount
+    data['behinderror'] = current.behinderror
+    data['branches'] = current.branches
     return data
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/hghaveaddon.py	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,14 @@
+import hghave
+
+@hghave.check("docgraph-ext", "Extension to generate graph from repository")
+def docgraph():
+    try:
+        import hgext.docgraph
+        hgext.docgraph.cmdtable # trigger import
+    except ImportError:
+        try:
+            import hgext3rd.docgraph
+            hgext3rd.docgraph.cmdtable # trigger import
+        except ImportError:
+            return False
+    return True
--- a/tests/test-discovery-obshashrange.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-discovery-obshashrange.t	Wed Sep 27 01:12:47 2017 +0200
@@ -79,11 +79,11 @@
   $ hg debugobsolete dddddddddddddddddddddddddddddddddddddddd `getid 'desc(r5)'` --config experimental.obshashrange.warm-cache=0
   $ hg debugobsolete eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee `getid 'desc(r7)'`
   $ hg debugobsolete
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 4de32a90b66cd083ebf3c00b41277aa7abca51dd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (*) {'user': 'test'} (glob)
+  eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 4de32a90b66cd083ebf3c00b41277aa7abca51dd 0 (*) {'user': 'test'} (glob)
 
   $ hg blackbox
   * @0000000000000000000000000000000000000000 (*)> log -G (glob)
@@ -160,9 +160,9 @@
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
   $ rm ../server/.hg/blackbox.log
   $ hg -R ../server/ debugobsolete --rev ::4 | sort
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
   $ rm ../server/.hg/blackbox.log
   $ hg blackbox
   * @0000000000000000000000000000000000000000 (*)> pull --rev 4 (glob)
@@ -176,9 +176,9 @@
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
   $ rm .hg/blackbox.log
   $ hg debugobsolete | sort
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
 
 testing simple push
 ===================
@@ -295,12 +295,12 @@
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
   $ rm ../server/.hg/blackbox.log
   $ hg -R ../server/ debugobsolete --rev ::tip | sort
-  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e 0 (*) {'user': 'test'} (glob)
   $ hg blackbox
   * @0000000000000000000000000000000000000000 (*)> debugobsolete (glob)
   * @0000000000000000000000000000000000000000 (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob)
@@ -346,12 +346,12 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
   $ rm .hg/blackbox.log
   $ hg debugobsolete | sort
-  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  ffffffffffffffffffffffffffffffffffffffff 45f8b879de922f6a6e620ba04205730335b6fc7e 0 (*) {'user': 'test'} (glob)
 
 testing pull with extra remote markers
 =====================================
@@ -405,14 +405,14 @@
   * @0000000000000000000000000000000000000000 (*)> blackbox (glob)
   $ rm ../server/.hg/blackbox.log
   $ hg -R ../server/ debugobsolete --rev '::6' | sort
-  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (*) {'user': 'test'} (glob)
+  aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (*) {'user': 'test'} (glob)
   $ hg blackbox
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> debugobsolete (glob)
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> alias 'debugobsolete' expands to 'debugobsolete -d '0 0'' (glob)
@@ -433,14 +433,14 @@
   * @45f8b879de922f6a6e620ba04205730335b6fc7e (*)> blackbox (glob)
   $ rm .hg/blackbox.log
   $ hg debugobsolete --rev '::6' | sort
-  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  111111111111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  22222222222222222bbbbbbbbbbbbb2222222222 2dc09a01254db841290af0538aa52f6f52c776e3 0 (*) {'user': 'test'} (glob)
+  aaaaaaa11111111aaaaaaaaa1111111111111111 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 66f7d451a68b85ed82ff5fcc254daf50c74144bd 0 (*) {'user': 'test'} (glob)
+  bbbbbbb2222222222bbbbbbbbbbbbb2222222222 bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 01241442b3c2bf3211e593b549c655ea65b295e3 0 (*) {'user': 'test'} (glob)
+  cccccccccccccccccccccccccccccccccccccccc bebd167eb94d257ace0e814aeb98e6972ed2970d 0 (*) {'user': 'test'} (glob)
+  dddddddddddddddddddddddddddddddddddddddd c8d03c1b5e94af74b772900c58259d2e08917735 0 (*) {'user': 'test'} (glob)
 
 Test cache behavior
 ===================
--- a/tests/test-divergent.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-divergent.t	Wed Sep 27 01:12:47 2017 +0200
@@ -47,13 +47,13 @@
   1 changesets pruned
   2 new divergent changesets
   $ hg log -G
-  @  3:e708fd28d5cf@default(draft) add bdivergent2 [divergent]
+  @  3:e708fd28d5cf@default(draft) add bdivergent2 [content-divergent]
   |
-  | o  2:c2f698071cba@default(draft) add bdivergent1 [divergent]
+  | o  2:c2f698071cba@default(draft) add bdivergent1 [content-divergent]
   |/
   o  0:135f39f4bd78@default(draft) add _a []
   
-  $ hg evolve --all --any --divergent
+  $ hg evolve --all --any --contentdivergent
   merge:[2] add bdivergent1
   with: [3] add bdivergent2
   base: [1] add _b
@@ -90,15 +90,15 @@
   1 changesets pruned
   2 new divergent changesets
   $ hg log -G
-  @  8:0a768ef678d9@default(draft) cdivergent2 [divergent]
+  @  8:0a768ef678d9@default(draft) cdivergent2 [content-divergent]
   |
-  | o  7:26c7705fee96@default(draft) add cdivergent1 [divergent]
+  | o  7:26c7705fee96@default(draft) add cdivergent1 [content-divergent]
   |/
   | o  5:c26f1d3baed2@default(draft) add bdivergent1 []
   |/
   o  0:135f39f4bd78@default(draft) add _a []
   
-  $ hg evolve --all --any --divergent
+  $ hg evolve --all --any --contentdivergent
   merge:[7] add cdivergent1
   with: [8] cdivergent2
   base: [6] add _c
@@ -126,9 +126,9 @@
   1 changesets pruned
   2 new divergent changesets
   $ hg log -G
-  @  3:e708fd28d5cf@default(draft) add bdivergent2 [divergent]
+  @  3:e708fd28d5cf@default(draft) add bdivergent2 [content-divergent]
   |
-  | o  2:c2f698071cba@default(draft) add bdivergent1 [divergent]
+  | o  2:c2f698071cba@default(draft) add bdivergent1 [content-divergent]
   |/
   o  0:135f39f4bd78@default(draft) add _a []
   
@@ -145,9 +145,9 @@
   > EOF
   $ hg evolve --all
   nothing to evolve on current working copy parent
-  (do you want to use --divergent)
+  (do you want to use --contentdivergent)
   [2]
-  $ hg evolve --divergent
+  $ hg evolve --contentdivergent
   merge:[3] add bdivergent2
   with: [2] add bdivergent1
   base: [1] add _b
--- a/tests/test-evolve-bumped.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-bumped.t	Wed Sep 27 01:12:47 2017 +0200
@@ -69,7 +69,7 @@
   no changes found
   1 new bumped changesets
 
-  $ hg evolve -a -A --bumped
+  $ hg evolve -a -A --phasedivergent
   recreate:[2] tweak a
   atop:[1] modify a
   computing new diff
@@ -121,5 +121,5 @@
   |
   o  0:d3873e73d99e@default(public) init
   
-  $ hg evolve --all --bumped
+  $ hg evolve --all --phasedivergent
   skipping b28e84916d8c : we do not handle merge yet
--- a/tests/test-evolve-cycles.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-cycles.t	Wed Sep 27 01:12:47 2017 +0200
@@ -86,48 +86,48 @@
 
   $ hg obslog "desc(A)" --hidden
   @  2a34000d3544 (1) A
-  |    rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  |    rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   |
   x  a8df460dbbfe (3) C
-  |    rewritten(description, parent, content) by test (*) as 2a34000d3544 (glob)
+  |    rewritten(description, parent, content) as 2a34000d3544 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-  |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   |
 
   $ hg obslog "desc(B)" --hidden
   @  2a34000d3544 (1) A
-  |    rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  |    rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   |
   x  a8df460dbbfe (3) C
-  |    rewritten(description, parent, content) by test (*) as 2a34000d3544 (glob)
+  |    rewritten(description, parent, content) as 2a34000d3544 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-  |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   |
 
   $ hg obslog "desc(C)" --hidden
   @  2a34000d3544 (1) A
-  |    rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  |    rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   |
   x  a8df460dbbfe (3) C
-  |    rewritten(description, parent, content) by test (*) as 2a34000d3544 (glob)
+  |    rewritten(description, parent, content) as 2a34000d3544 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-  |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   |
 
 Check that all option don't crash on a cycle either
 
   $ hg obslog "desc(C)" --hidden --all
   @  2a34000d3544 (1) A
-  |    rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  |    rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   |
   x  a8df460dbbfe (3) C
-  |    rewritten(description, parent, content) by test (*) as 2a34000d3544 (glob)
+  |    rewritten(description, parent, content) as 2a34000d3544 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-  |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   |
 
 Test with multiple cyles
@@ -243,185 +243,185 @@
 
   $ hg obslog "desc(D)" --hidden
   x  0da815c333f6 (5) E
-  |    rewritten(description, parent, content) by test (*) as d9f908fde1a1 (glob)
+  |    rewritten(description, parent, content) as d9f908fde1a1 by test (*) (glob)
   |
   @    868d2e0eb19c (4) D
-  |\     rewritten(description, parent, content) by test (*) as 0da815c333f6 (glob)
+  |\     rewritten(description, parent, content) as 0da815c333f6 by test (*) (glob)
   | |
   | x  d9f908fde1a1 (6) F
-  | |    rewritten(description, parent, content) by test (*) as 868d2e0eb19c (glob)
+  | |    rewritten(description, parent, content) as 868d2e0eb19c by test (*) (glob)
   | |
   +---x  2a34000d3544 (1) A
-  | |      rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  | |      rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   | |
   x |  a8df460dbbfe (3) C
-  | |    rewritten(description, parent, content) by test (*) as 2a34000d3544, 868d2e0eb19c (glob)
+  | |    rewritten(description, parent, content) as 2a34000d3544, 868d2e0eb19c by test (*) (glob)
   | |
   x |  c473644ee0e9 (2) B
-  | |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  | |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   | |
 Check that all option don't crash either on a cycle
   $ hg obslog --all --hidden "desc(F)"
   x  0da815c333f6 (5) E
-  |    rewritten(description, parent, content) by test (*) as d9f908fde1a1 (glob)
+  |    rewritten(description, parent, content) as d9f908fde1a1 by test (*) (glob)
   |
   @    868d2e0eb19c (4) D
-  |\     rewritten(description, parent, content) by test (*) as 0da815c333f6 (glob)
+  |\     rewritten(description, parent, content) as 0da815c333f6 by test (*) (glob)
   | |
   | x  d9f908fde1a1 (6) F
-  | |    rewritten(description, parent, content) by test (*) as 868d2e0eb19c (glob)
+  | |    rewritten(description, parent, content) as 868d2e0eb19c by test (*) (glob)
   | |
   +---x  2a34000d3544 (1) A
-  | |      rewritten(description, parent, content) by test (*) as c473644ee0e9 (glob)
+  | |      rewritten(description, parent, content) as c473644ee0e9 by test (*) (glob)
   | |
   x |  a8df460dbbfe (3) C
-  | |    rewritten(description, parent, content) by test (*) as 2a34000d3544, 868d2e0eb19c (glob)
+  | |    rewritten(description, parent, content) as 2a34000d3544, 868d2e0eb19c by test (*) (glob)
   | |
   x |  c473644ee0e9 (2) B
-  | |    rewritten(description, parent, content) by test (*) as a8df460dbbfe (glob)
+  | |    rewritten(description, parent, content) as a8df460dbbfe by test (*) (glob)
   | |
 Check the json output is valid in this case
 
   $ hg obslog "desc(D)" --hidden --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0
+                  ],
+                  "effect": [
+                      *, (glob)
+                      "parent",
+                      "content"
+                  ],
+                  "succnodes": [
+                      "0da815c333f6"
+                  ],
+                  "user": "test",
+                  "verb": "rewritten"
+              }
+          ],
+          "node": "868d2e0eb19c",
+          "rev": 4,
+          "shortdescription": "D"
+      },
+      {
+          "markers": [
+              {
+                  "date": [
+                      *, (glob)
+                      0
+                  ],
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
+                  "succnodes": [
+                      "868d2e0eb19c"
+                  ],
+                  "user": "test",
+                  "verb": "rewritten"
+              }
+          ],
+          "node": "d9f908fde1a1",
+          "rev": 6,
+          "shortdescription": "F"
+      },
+      {
+          "markers": [
+              {
+                  "date": [
                       *, (glob)
                       0
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
-                      "0da815c333f6"
-                  ],
-                  "debugobshistory.verb": "rewritten"
-              }
-          ],
-          "debugobshistory.node": "868d2e0eb19c",
-          "debugobshistory.rev": 4,
-          "debugobshistory.shortdescription": "D"
-      },
-      {
-          "debugobshistory.markers": [
-              {
-                  "debugobshistory.effect": [
-                      "description",
-                      "parent",
-                      "content"
-                  ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
-                      "868d2e0eb19c"
-                  ],
-                  "debugobshistory.verb": "rewritten"
-              }
-          ],
-          "debugobshistory.node": "d9f908fde1a1",
-          "debugobshistory.rev": 6,
-          "debugobshistory.shortdescription": "F"
-      },
-      {
-          "debugobshistory.markers": [
-              {
-                  "debugobshistory.effect": [
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
+                  "succnodes": [
+                      "d9f908fde1a1"
+                  ],
+                  "user": "test",
+                  "verb": "rewritten"
+              }
+          ],
+          "node": "0da815c333f6",
+          "rev": 5,
+          "shortdescription": "E"
+      },
+      {
+          "markers": [
+              {
+                  "date": [
                       *, (glob)
                       0
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
-                      "d9f908fde1a1"
-                  ],
-                  "debugobshistory.verb": "rewritten"
-              }
-          ],
-          "debugobshistory.node": "0da815c333f6",
-          "debugobshistory.rev": 5,
-          "debugobshistory.shortdescription": "E"
-      },
-      {
-          "debugobshistory.markers": [
-              {
-                  "debugobshistory.effect": [
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "2a34000d3544",
                       "868d2e0eb19c"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "a8df460dbbfe",
-          "debugobshistory.rev": 3,
-          "debugobshistory.shortdescription": "C"
+          "node": "a8df460dbbfe",
+          "rev": 3,
+          "shortdescription": "C"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0
+                  ],
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
+                  "succnodes": [
+                      "a8df460dbbfe"
+                  ],
+                  "user": "test",
+                  "verb": "rewritten"
+              }
+          ],
+          "node": "c473644ee0e9",
+          "rev": 2,
+          "shortdescription": "B"
+      },
+      {
+          "markers": [
+              {
+                  "date": [
                       *, (glob)
                       0
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
-                      "a8df460dbbfe"
-                  ],
-                  "debugobshistory.verb": "rewritten"
-              }
-          ],
-          "debugobshistory.node": "c473644ee0e9",
-          "debugobshistory.rev": 2,
-          "debugobshistory.shortdescription": "B"
-      },
-      {
-          "debugobshistory.markers": [
-              {
-                  "debugobshistory.effect": [
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "c473644ee0e9"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "2a34000d3544",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A"
+          "node": "2a34000d3544",
+          "rev": 1,
+          "shortdescription": "A"
       }
   ]
 
--- a/tests/test-evolve-effectflags.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-effectflags.t	Wed Sep 27 01:12:47 2017 +0200
@@ -34,7 +34,13 @@
   @  fdf9bde5129a (2) A1
   |
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
+  
+  $ hg log --hidden -r "desc(A0)"
+  changeset:   1:471f378eab4c
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     A0
   
 
 amend touching the user only
@@ -51,7 +57,13 @@
   @  5485c92d3433 (4) B0
   |
   x  ef4a313b1e0a (3) B0
-       rewritten(user) by test (*) as 5485c92d3433 (glob)
+       rewritten(user) as 5485c92d3433 by test (*) (glob)
+  
+  $ hg log --hidden -r "ef4a313b1e0a"
+  changeset:   3:ef4a313b1e0a
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     B0
   
 
 amend touching the date only
@@ -68,7 +80,13 @@
   @  4dd84345082e (6) B1
   |
   x  2ef0680ff450 (5) B1
-       rewritten(date) by test (*) as 4dd84345082e (glob)
+       rewritten(date) as 4dd84345082e by test (*) (glob)
+  
+  $ hg log --hidden -r "2ef0680ff450"
+  changeset:   5:2ef0680ff450
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     B1
   
 
 amend touching the branch only
@@ -89,7 +107,13 @@
   @  14a01456e057 (9) B2
   |
   x  bd3db8264cee (7) B2
-       rewritten(branch) by test (*) as 14a01456e057 (glob)
+       rewritten(branch) as 14a01456e057 by test (*) (glob)
+  
+  $ hg log --hidden -r "bd3db8264cee"
+  changeset:   7:bd3db8264cee
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     B2
   
 
   $ hg up default
@@ -111,7 +135,13 @@
   @  da86aa2f19a3 (12) D0
   |
   x  c85eff83a034 (11) D0
-       rewritten(parent) by test (*) as da86aa2f19a3 (glob)
+       rewritten(parent) as da86aa2f19a3 by test (*) (glob)
+  
+  $ hg log --hidden -r "c85eff83a034"
+  changeset:   11:c85eff83a034
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     D0
   
 
 amend touching the diff
@@ -130,7 +160,13 @@
   @  75781fdbdbf5 (15) E0
   |
   x  ebfe0333e0d9 (13) E0
-       rewritten(content) by test (*) as 75781fdbdbf5 (glob)
+       rewritten(content) as 75781fdbdbf5 by test (*) (glob)
+  
+  $ hg log --hidden -r "ebfe0333e0d9"
+  changeset:   13:ebfe0333e0d9
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     E0
   
 
 amend with multiple effect (desc and meta)
@@ -150,8 +186,15 @@
   @  a94e0fd5f1c8 (18) F1
   |
   x  fad47e5bd78e (16) F0
-       rewritten(description, user, date, branch) by test (*) as a94e0fd5f1c8 (glob)
+       rewritten(description, user, date, branch) as a94e0fd5f1c8 by test (*) (glob)
   
+  $ hg log --hidden -r "fad47e5bd78e"
+  changeset:   16:fad47e5bd78e
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     F0
+  
+
 rebase not touching the diff
 ----------------------------
 
@@ -197,7 +240,14 @@
   o  e509e2eb3df5 (22) H1
   |
   x  b57fed8d8322 (20) H1
-       rewritten(parent) by test (*) as e509e2eb3df5 (glob)
+       rewritten(parent) as e509e2eb3df5 by test (*) (glob)
+  
+  $ hg log --hidden -r "b57fed8d8322"
+  changeset:   20:b57fed8d8322
+  branch:      my-other-branch
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     H1
   
 amend closing the branch should be detected as meta change
 ----------------------------------------------------------
@@ -214,5 +264,12 @@
   @  12c6238b5e37 (26) I0
   |
   x  2f599e54c1c6 (24) I0
-       rewritten(meta) by test (*) as 12c6238b5e37 (glob)
+       rewritten(meta) as 12c6238b5e37 by test (*) (glob)
   
+  $ hg log --hidden -r "2f599e54c1c6"
+  changeset:   24:2f599e54c1c6
+  branch:      closedbranch
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     I0
+  
--- a/tests/test-evolve-list.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-list.t	Wed Sep 27 01:12:47 2017 +0200
@@ -23,7 +23,7 @@
     unstable: cb9a9f314b8b (obsolete parent)
   
   177f92b77385: c
-    unstable: d2ae7f538514 (unstable parent)
+    orphan: d2ae7f538514 (orphan parent)
   
   $ cd ..
 
--- a/tests/test-evolve-obshistory-complex.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-obshistory-complex.t	Wed Sep 27 01:12:47 2017 +0200
@@ -362,25 +362,25 @@
   o    7b3290f6e0a0 (12) fold1
   |\
   x |    d15d0ffc75f6 (8) fold1
-  |\ \     rewritten(parent, content) by test (*) as 7b3290f6e0a0, d0f33db50670 (glob)
+  |\ \     rewritten(parent, content) as 7b3290f6e0a0, d0f33db50670 by test (*) (glob)
   | | |
   | | x  e036916b63ea (11) fold0
-  | | |    rewritten(description, parent, content) by test (*) as 7b3290f6e0a0 (glob)
+  | | |    rewritten(description, parent, content) as 7b3290f6e0a0 by test (*) (glob)
   | | |
   x | |  868d2e0eb19c (4) D
-   / /     rewritten(description, parent, content) by test (*) as d15d0ffc75f6 (glob)
+   / /     rewritten(description, parent, content) as d15d0ffc75f6 by test (*) (glob)
   | |
   x |  a8df460dbbfe (3) C
-   /     rewritten(description, content) by test (*) as d15d0ffc75f6 (glob)
+   /     rewritten(description, content) as d15d0ffc75f6 by test (*) (glob)
   |
   x    b868bc49b0a4 (7) fold0
-  |\     rewritten(parent, content) by test (*) as 19e14c8397fc, e036916b63ea (glob)
+  |\     rewritten(parent, content) as 19e14c8397fc, e036916b63ea by test (*) (glob)
   | |
   x |  2a34000d3544 (1) A
-   /     rewritten(description, content) by test (*) as b868bc49b0a4 (glob)
+   /     rewritten(description, content) as b868bc49b0a4 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-       rewritten(description, parent, content) by test (*) as b868bc49b0a4 (glob)
+       rewritten(description, parent, content) as b868bc49b0a4 by test (*) (glob)
   
 While with all option, we should see 15 changesets
 
@@ -394,35 +394,35 @@
   | | | | o  ec31316faa9d (14) fold2
   | | | |/|
   | | | x |    100cc25b765f (9) fold2
-  | | | |\ \     rewritten(parent, content) by test (*) as d4a000f63ee9, ec31316faa9d (glob)
+  | | | |\ \     rewritten(parent, content) as d4a000f63ee9, ec31316faa9d by test (*) (glob)
   | | | | | |
   | +-------x  d0f33db50670 (13) fold1
-  | | | | |      rewritten(description, parent, content) by test (*) as ec31316faa9d (glob)
+  | | | | |      rewritten(description, parent, content) as ec31316faa9d by test (*) (glob)
   | | | | |
   +---x | |  e036916b63ea (11) fold0
-  | |  / /     rewritten(description, parent, content) by test (*) as 7b3290f6e0a0 (glob)
+  | |  / /     rewritten(description, parent, content) as 7b3290f6e0a0 by test (*) (glob)
   | | | |
   | | x |  0da815c333f6 (5) E
-  | |  /     rewritten(description, content) by test (*) as 100cc25b765f (glob)
+  | |  /     rewritten(description, content) as 100cc25b765f by test (*) (glob)
   | | |
   x | |    b868bc49b0a4 (7) fold0
-  |\ \ \     rewritten(parent, content) by test (*) as 19e14c8397fc, e036916b63ea (glob)
+  |\ \ \     rewritten(parent, content) as 19e14c8397fc, e036916b63ea by test (*) (glob)
   | | | |
   | | x |    d15d0ffc75f6 (8) fold1
-  | | |\ \     rewritten(parent, content) by test (*) as 7b3290f6e0a0, d0f33db50670 (glob)
+  | | |\ \     rewritten(parent, content) as 7b3290f6e0a0, d0f33db50670 by test (*) (glob)
   | | | | |
   | | | | x  d9f908fde1a1 (6) F
-  | | | |      rewritten(description, parent, content) by test (*) as 100cc25b765f (glob)
+  | | | |      rewritten(description, parent, content) as 100cc25b765f by test (*) (glob)
   | | | |
   x | | |  2a34000d3544 (1) A
-   / / /     rewritten(description, content) by test (*) as b868bc49b0a4 (glob)
+   / / /     rewritten(description, content) as b868bc49b0a4 by test (*) (glob)
   | | |
   | x |  868d2e0eb19c (4) D
-  |  /     rewritten(description, parent, content) by test (*) as d15d0ffc75f6 (glob)
+  |  /     rewritten(description, parent, content) as d15d0ffc75f6 by test (*) (glob)
   | |
   | x  a8df460dbbfe (3) C
-  |      rewritten(description, content) by test (*) as d15d0ffc75f6 (glob)
+  |      rewritten(description, content) as d15d0ffc75f6 by test (*) (glob)
   |
   x  c473644ee0e9 (2) B
-       rewritten(description, parent, content) by test (*) as b868bc49b0a4 (glob)
+       rewritten(description, parent, content) as b868bc49b0a4 by test (*) (glob)
   
--- a/tests/test-evolve-obshistory.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-obshistory.t	Wed Sep 27 01:12:47 2017 +0200
@@ -60,7 +60,7 @@
   @  4ae3a4151de9 (3) A1
   |
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as 4ae3a4151de9 (glob)
+       rewritten(description, content) as 4ae3a4151de9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/4ae3a4151de9-changeset-description
          @@ -1,1 +1,3 @@
@@ -77,40 +77,66 @@
          +42
   
   
+
+  $ hg obslog --no-graph --patch 4ae3a4151de9
+  4ae3a4151de9 (3) A1
+  471f378eab4c (1) A0
+    rewritten(description, content) as 4ae3a4151de9 by test (*) (glob)
+      --- a/471f378eab4c-changeset-description	
+      +++ b/4ae3a4151de9-changeset-description	
+      @@ -1,1 +1,3 @@
+      -A0
+      +A1
+      +
+      +Better commit message
+  
+      diff -r 471f378eab4c -r 4ae3a4151de9 A0
+      --- a/A0	Thu Jan 01 00:00:00 1970 +0000
+      +++ b/A0	Thu Jan 01 00:00:00 1970 +0000
+      @@ -1,1 +1,2 @@
+       A0
+      +42
+  
+
+  $ hg obslog 4ae3a4151de9 --graph -T'{label("log.summary", shortdescription)} {if(markers, join(markers % "at {date|hgdate} by {user|person} ", " also "))}'
+  @  A1
+  |
+  x  A0 at * by test (glob)
+  
   $ hg obslog 4ae3a4151de9 --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "4ae3a4151de9",
-          "debugobshistory.rev": 3,
-          "debugobshistory.shortdescription": "A1"
+          "markers": [],
+          "node": "4ae3a4151de9",
+          "rev": 3,
+          "shortdescription": "A1"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       "description",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "4ae3a4151de9"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
   $ hg obslog --hidden --patch 471f378eab4c
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as 4ae3a4151de9 (glob)
+       rewritten(description, content) as 4ae3a4151de9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/4ae3a4151de9-changeset-description
          @@ -1,1 +1,3 @@
@@ -130,26 +156,26 @@
   $ hg obslog --hidden 471f378eab4c --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      *, (glob)
-                      "content"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      *, (glob)
+                      "content"
+                  ],
+                  "succnodes": [
                       "4ae3a4151de9"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
   $ hg update 471f378eab4c
@@ -222,19 +248,19 @@
   $ hg obslog 'desc(B0)' --hidden --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.verb": "pruned"
+                  "user": "test",
+                  "verb": "pruned"
               }
           ],
-          "debugobshistory.node": "0dec01379d3b",
-          "debugobshistory.rev": 2,
-          "debugobshistory.shortdescription": "B0"
+          "node": "0dec01379d3b",
+          "rev": 2,
+          "shortdescription": "B0"
       }
   ]
   $ hg obslog 'desc(A0)' --patch
@@ -243,10 +269,10 @@
   $ hg obslog 'desc(A0)' --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "markers": [],
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
   $ hg up 1
@@ -350,33 +376,33 @@
 Check that debugobshistory on splitted commit show both targets
   $ hg obslog 471597cad322 --hidden --patch
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
   $ hg obslog 471597cad322 --hidden --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      "parent",
-                      "content"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "parent",
+                      "content"
+                  ],
+                  "succnodes": [
                       "337fec4d2edc",
                       "f257fde29c7a"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471597cad322",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471597cad322",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
 Check that debugobshistory on the first successor after split show
@@ -385,7 +411,7 @@
   o  337fec4d2edc (2) A0
   |
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
 With the all option, it should show the three changesets
@@ -395,7 +421,7 @@
   | @  f257fde29c7a (3) A0
   |/
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
 Check that debugobshistory on the second successor after split show
@@ -404,7 +430,7 @@
   @  f257fde29c7a (3) A0
   |
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
 With the all option, it should show the three changesets
@@ -414,7 +440,7 @@
   | @  f257fde29c7a (3) A0
   |/
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
 Obslog with all option all should also works on the splitted commit
@@ -424,7 +450,7 @@
   | @  f257fde29c7a (3) A0
   |/
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
 Check that debugobshistory on both successors after split show
@@ -435,7 +461,7 @@
   | @  f257fde29c7a (3) A0
   |/
   x  471597cad322 (1) A0
-       rewritten(parent, content) by test (*) as 337fec4d2edc, f257fde29c7a (glob)
+       rewritten(parent, content) as 337fec4d2edc, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (2))
   
   $ hg update 471597cad322
@@ -602,7 +628,7 @@
 
   $ hg obslog de7290d8b885 --hidden --patch
   x  de7290d8b885 (1) A0
-       rewritten(parent, content) by test (*) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a (glob)
+       rewritten(parent, content) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (4))
   
   $ hg obslog de7290d8b885 --hidden --all --patch
@@ -615,76 +641,76 @@
   | o  f257fde29c7a (3) A0
   |/
   x  de7290d8b885 (1) A0
-       rewritten(parent, content) by test (*) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a (glob)
+       rewritten(parent, content) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (4))
   
   $ hg obslog de7290d8b885 --hidden --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "1ae8bc733a14",
                       "337fec4d2edc",
                       "c7f044602e9b",
                       "f257fde29c7a"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "de7290d8b885",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "de7290d8b885",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
   $ hg obslog c7f044602e9b --patch
   @  c7f044602e9b (5) A0
   |
   x  de7290d8b885 (1) A0
-       rewritten(parent, content) by test (*) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a (glob)
+       rewritten(parent, content) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (4))
   
   $ hg obslog c7f044602e9b --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "c7f044602e9b",
-          "debugobshistory.rev": 5,
-          "debugobshistory.shortdescription": "A0"
+          "markers": [],
+          "node": "c7f044602e9b",
+          "rev": 5,
+          "shortdescription": "A0"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "1ae8bc733a14",
                       "337fec4d2edc",
                       "c7f044602e9b",
                       "f257fde29c7a"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "de7290d8b885",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "de7290d8b885",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
 Check that debugobshistory on all heads show a coherent graph
@@ -698,7 +724,7 @@
   | o  f257fde29c7a (3) A0
   |/
   x  de7290d8b885 (1) A0
-       rewritten(parent, content) by test (*) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a (glob)
+       rewritten(parent, content) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (4))
   
   $ hg obslog 5 --all --patch
@@ -711,7 +737,7 @@
   | o  f257fde29c7a (3) A0
   |/
   x  de7290d8b885 (1) A0
-       rewritten(parent, content) by test (*) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a (glob)
+       rewritten(parent, content) as 1ae8bc733a14, 337fec4d2edc, c7f044602e9b, f257fde29c7a by test (*) (glob)
          (No patch available yet, too many successors (4))
   
   $ hg update de7290d8b885
@@ -784,7 +810,7 @@
 the revision with the target
   $ hg obslog --hidden 471f378eab4c --patch
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+       rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/eb5a0daa2192-changeset-description
          @@ -1,1 +1,1 @@
@@ -803,11 +829,11 @@
   @    eb5a0daa2192 (3) C0
   |\
   x |  0dec01379d3b (2) B0
-   /     rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+   /     rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
   |        (No patch available yet, changesets rebased)
   |
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+       rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/eb5a0daa2192-changeset-description
          @@ -1,1 +1,1 @@
@@ -825,7 +851,7 @@
 the revision with the target
   $ hg obslog --hidden 0dec01379d3b --patch
   x  0dec01379d3b (2) B0
-       rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+       rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
          (No patch available yet, changesets rebased)
   
 Check that with all option, all changesets are shown
@@ -833,11 +859,11 @@
   @    eb5a0daa2192 (3) C0
   |\
   x |  0dec01379d3b (2) B0
-   /     rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+   /     rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
   |        (No patch available yet, changesets rebased)
   |
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+       rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/eb5a0daa2192-changeset-description
          @@ -1,1 +1,1 @@
@@ -857,11 +883,11 @@
   @    eb5a0daa2192 (3) C0
   |\
   x |  0dec01379d3b (2) B0
-   /     rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+   /     rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
   |        (No patch available yet, changesets rebased)
   |
   x  471f378eab4c (1) A0
-       rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+       rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/eb5a0daa2192-changeset-description
          @@ -1,1 +1,1 @@
@@ -878,55 +904,55 @@
   $ hg obslog eb5a0daa2192 --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "eb5a0daa2192",
-          "debugobshistory.rev": 3,
-          "debugobshistory.shortdescription": "C0"
+          "markers": [],
+          "node": "eb5a0daa2192",
+          "rev": 3,
+          "shortdescription": "C0"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      "description",
-                      "content"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      *, (glob)
+                      "content"
+                  ],
+                  "succnodes": [
                       "eb5a0daa2192"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       "description",
                       "parent",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "eb5a0daa2192"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "0dec01379d3b",
-          "debugobshistory.rev": 2,
-          "debugobshistory.shortdescription": "B0"
+          "node": "0dec01379d3b",
+          "rev": 2,
+          "shortdescription": "B0"
       }
   ]
   $ hg update 471f378eab4c
@@ -1015,14 +1041,14 @@
 Check that debugobshistory on the divergent revision show both destinations
   $ hg obslog --hidden 471f378eab4c --patch
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1038,14 +1064,14 @@
   | o  fdf9bde5129a (2) A1
   |/
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1056,39 +1082,39 @@
   $ hg obslog --hidden 471f378eab4c --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      "description"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "description"
+                  ],
+                  "succnodes": [
                       "65b757b745b9"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               },
               {
-                  "debugobshistory.effect": [
-                      "description"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "description"
+                  ],
+                  "succnodes": [
                       "fdf9bde5129a"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
 Check that debugobshistory on the first diverged revision show the revision
@@ -1097,14 +1123,14 @@
   o  fdf9bde5129a (2) A1
   |
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1120,14 +1146,14 @@
   | o  fdf9bde5129a (2) A1
   |/
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1141,14 +1167,14 @@
   @  65b757b745b9 (3) A2
   |
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1163,14 +1189,14 @@
   | o  fdf9bde5129a (2) A1
   |/
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1186,14 +1212,14 @@
   | o  fdf9bde5129a (2) A1
   |/
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as 65b757b745b9 (glob)
+       rewritten(description) as 65b757b745b9 by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/65b757b745b9-changeset-description
          @@ -1,1 +1,1 @@
          -A0
          +A2
   
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1204,51 +1230,51 @@
   $ hg obslog '65b757b745b9+fdf9bde5129a' --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "65b757b745b9",
-          "debugobshistory.rev": 3,
-          "debugobshistory.shortdescription": "A2"
+          "markers": [],
+          "node": "65b757b745b9",
+          "rev": 3,
+          "shortdescription": "A2"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      "description"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "description"
+                  ],
+                  "succnodes": [
                       "65b757b745b9"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               },
               {
-                  "debugobshistory.effect": [
-                      "description"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "description"
+                  ],
+                  "succnodes": [
                       "fdf9bde5129a"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       },
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "fdf9bde5129a",
-          "debugobshistory.rev": 2,
-          "debugobshistory.shortdescription": "A1"
+          "markers": [],
+          "node": "fdf9bde5129a",
+          "rev": 2,
+          "shortdescription": "A1"
       }
   ]
   $ hg update 471f378eab4c
@@ -1258,7 +1284,7 @@
   $ hg update --hidden 'desc(A0)'
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   working directory parent is obsolete! (471f378eab4c)
-  (471f378eab4c has diverged, use 'hg evolve --list --divergent' to resolve the issue)
+  (471f378eab4c has diverged, use 'hg evolve --list --contentdivergent' to resolve the issue)
 
 Test output with amended + folded commit
 ========================================
@@ -1335,7 +1361,7 @@
   @    eb5a0daa2192 (4) C0
   |\
   x |  471f378eab4c (1) A0
-   /     rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+   /     rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
   |        --- a/471f378eab4c-changeset-description
   |        +++ b/eb5a0daa2192-changeset-description
   |        @@ -1,1 +1,1 @@
@@ -1350,11 +1376,11 @@
   |
   |
   x  b7ea6d14e664 (3) B1
-  |    rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+  |    rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
   |      (No patch available yet, changesets rebased)
   |
   x  0dec01379d3b (2) B0
-       rewritten(description) by test (*) as b7ea6d14e664 (glob)
+       rewritten(description) as b7ea6d14e664 by test (*) (glob)
          --- a/0dec01379d3b-changeset-description
          +++ b/b7ea6d14e664-changeset-description
          @@ -1,1 +1,1 @@
@@ -1367,7 +1393,7 @@
   @    eb5a0daa2192 (4) C0
   |\
   x |  471f378eab4c (1) A0
-   /     rewritten(description, content) by test (*) as eb5a0daa2192 (glob)
+   /     rewritten(description, content) as eb5a0daa2192 by test (*) (glob)
   |        --- a/471f378eab4c-changeset-description
   |        +++ b/eb5a0daa2192-changeset-description
   |        @@ -1,1 +1,1 @@
@@ -1382,11 +1408,11 @@
   |
   |
   x  b7ea6d14e664 (3) B1
-  |    rewritten(description, parent, content) by test (*) as eb5a0daa2192 (glob)
+  |    rewritten(description, parent, content) as eb5a0daa2192 by test (*) (glob)
   |      (No patch available yet, changesets rebased)
   |
   x  0dec01379d3b (2) B0
-       rewritten(description) by test (*) as b7ea6d14e664 (glob)
+       rewritten(description) as b7ea6d14e664 by test (*) (glob)
          --- a/0dec01379d3b-changeset-description
          +++ b/b7ea6d14e664-changeset-description
          @@ -1,1 +1,1 @@
@@ -1397,76 +1423,76 @@
   $ hg obslog eb5a0daa2192 --no-graph -Tjson | python -m json.tool
   [
       {
-          "debugobshistory.markers": [],
-          "debugobshistory.node": "eb5a0daa2192",
-          "debugobshistory.rev": 4,
-          "debugobshistory.shortdescription": "C0"
+          "markers": [],
+          "node": "eb5a0daa2192",
+          "rev": 4,
+          "shortdescription": "C0"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       *, (glob)
                       *, (glob)
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "eb5a0daa2192"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "b7ea6d14e664",
-          "debugobshistory.rev": 3,
-          "debugobshistory.shortdescription": "B1"
+          "node": "b7ea6d14e664",
+          "rev": 3,
+          "shortdescription": "B1"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
-                      "description"
-                  ],
-                  "debugobshistory.marker_date": [
+                  "date": [
                       *, (glob)
                       0 (glob)
                   ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "effect": [
+                      "description"
+                  ],
+                  "succnodes": [
                       "b7ea6d14e664"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "0dec01379d3b",
-          "debugobshistory.rev": 2,
-          "debugobshistory.shortdescription": "B0"
+          "node": "0dec01379d3b",
+          "rev": 2,
+          "shortdescription": "B0"
       },
       {
-          "debugobshistory.markers": [
+          "markers": [
               {
-                  "debugobshistory.effect": [
+                  "date": [
+                      *, (glob)
+                      0 (glob)
+                  ],
+                  "effect": [
                       "description",
                       "content"
                   ],
-                  "debugobshistory.marker_date": [
-                      *, (glob)
-                      0 (glob)
-                  ],
-                  "debugobshistory.marker_user": "test",
-                  "debugobshistory.succnodes": [
+                  "succnodes": [
                       "eb5a0daa2192"
                   ],
-                  "debugobshistory.verb": "rewritten"
+                  "user": "test",
+                  "verb": "rewritten"
               }
           ],
-          "debugobshistory.node": "471f378eab4c",
-          "debugobshistory.rev": 1,
-          "debugobshistory.shortdescription": "A0"
+          "node": "471f378eab4c",
+          "rev": 1,
+          "shortdescription": "A0"
       }
   ]
   $ hg update 471f378eab4c
@@ -1562,7 +1588,7 @@
   @  7a230b46bf61 (3) A2
   |
   x  fdf9bde5129a (2) A1
-  |    rewritten(description) by test (*) as 7a230b46bf61 (glob)
+  |    rewritten(description) as 7a230b46bf61 by test (*) (glob)
   |      --- a/fdf9bde5129a-changeset-description
   |      +++ b/7a230b46bf61-changeset-description
   |      @@ -1,1 +1,1 @@
@@ -1571,7 +1597,7 @@
   |
   |
   x  471f378eab4c (1) A0
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          --- a/471f378eab4c-changeset-description
          +++ b/fdf9bde5129a-changeset-description
          @@ -1,1 +1,1 @@
@@ -1597,21 +1623,21 @@
   o  7a230b46bf61 (2) A2
   |
   x  fdf9bde5129a
-  |    rewritten(description) by test (*) as 7a230b46bf61 (glob)
+  |    rewritten(description) as 7a230b46bf61 by test (*) (glob)
   |      (No patch available yet, context is not local)
   |
   @  471f378eab4c (1) A0
-       rewritten(description) by test (*) as fdf9bde5129a (glob)
+       rewritten(description) as fdf9bde5129a by test (*) (glob)
          (No patch available yet, succ is unknown locally)
   
   $ hg obslog 7a230b46bf61 --color=debug --patch
   o  [evolve.node|7a230b46bf61] [evolve.rev|(2)] [evolve.short_description|A2]
   |
   x  [evolve.node evolve.missing_change_ctx|fdf9bde5129a]
-  |    [evolve.verb|rewritten](description) by [evolve.user|test] [evolve.date|(*)] as [evolve.node|7a230b46bf61] (glob)
+  |    [evolve.verb|rewritten](description) as [evolve.node|7a230b46bf61] by [evolve.user|test] [evolve.date|(*)] (glob)
   |      (No patch available yet, context is not local)
   |
   @  [evolve.node|471f378eab4c] [evolve.rev|(1)] [evolve.short_description|A0]
-       [evolve.verb|rewritten](description) by [evolve.user|test] [evolve.date|(*)] as [evolve.node|fdf9bde5129a] (glob)
+       [evolve.verb|rewritten](description) as [evolve.node|fdf9bde5129a] by [evolve.user|test] [evolve.date|(*)] (glob)
          (No patch available yet, succ is unknown locally)
   
--- a/tests/test-evolve-templates.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-templates.t	Wed Sep 27 01:12:47 2017 +0200
@@ -73,10 +73,10 @@
   o  d004c8f274b9 (4) A2
   |
   x  a468dc9b3633 (3) A1
-  |    rewritten(description) by test2 (*) as d004c8f274b9 (glob)
+  |    rewritten(description) as d004c8f274b9 by test2 (*) (glob)
   |
   @  471f378eab4c (1) A0
-       rewritten(description, content) by test1 (*) as a468dc9b3633 (glob)
+       rewritten(description, content) as a468dc9b3633 by test1 (*) (glob)
   
   $ hg tlog
   o  d004c8f274b9
@@ -120,7 +120,6 @@
   |      semi-colon: [a468dc9b3633]
   o  ea207398892e
   
-
   $ hg up 'desc(A2)'
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg tlog
@@ -460,7 +459,7 @@
   $ hg up 'desc(A0)' --hidden
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   working directory parent is obsolete! (471f378eab4c)
-  (471f378eab4c has diverged, use 'hg evolve --list --divergent' to resolve the issue)
+  (471f378eab4c has diverged, use 'hg evolve --list --contentdivergent' to resolve the issue)
 
 Precursors template should show current revision as it is the working copy
   $ hg tlog
--- a/tests/test-evolve-topic.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve-topic.t	Wed Sep 27 01:12:47 2017 +0200
@@ -31,12 +31,15 @@
   $ mkcommit aaa
   $ mkcommit bbb
   $ hg topic foo
+  marked working directory as topic: foo
   $ mkcommit ccc
+  active topic 'foo' grew its first changeset
   $ mkcommit ddd
   $ mkcommit eee
   $ mkcommit fff
   $ hg topic bar
   $ mkcommit ggg
+  active topic 'bar' grew its first changeset
   $ mkcommit hhh
   $ mkcommit iii
   $ mkcommit jjj
@@ -74,6 +77,7 @@
   $ hg topic -l 
   ### topic: foo (?)
   ### branch: default (?)
+  ### target: default (branch)
   t4@ add fff (current)
   t3: add eee
   t2: add ddd
--- a/tests/test-evolve.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-evolve.t	Wed Sep 27 01:12:47 2017 +0200
@@ -413,7 +413,7 @@
   |
   o  0	: base - test
   
-  $ hg evolve --any --traceback --bumped
+  $ hg evolve --any --traceback --phasedivergent
   recreate:[8] another feature that rox
   atop:[7] another feature (child of ba0ec09b1bab)
   computing new diff
@@ -454,9 +454,9 @@
   $ hg log -G --template '{rev} {troubles}\n'
   @  13
   |
-  | o  11 unstable
+  | o  11 orphan
   | |
-  | o  10 unstable
+  | o  10 orphan
   | |
   | x  9
   |/
@@ -771,12 +771,12 @@
   @    d26d339c513f (12) add 4
   |\
   x |    af636757ce3b (11) add 3
-  |\ \     rewritten(description, user, parent, content) by test (*) as d26d339c513f (glob)
+  |\ \     rewritten(description, user, parent, content) as d26d339c513f by test (*) (glob)
   | | |
   | \ \
   | |\ \
   | | | x  ce341209337f (4) add 4
-  | | |      rewritten(description, user, content) by test (*) as d26d339c513f (glob)
+  | | |      rewritten(description, user, content) as d26d339c513f by test (*) (glob)
   | | |
 
 Test obsstore stat
@@ -972,7 +972,7 @@
   
   $ hg evolve
   nothing to evolve on current working copy parent
-  (2 other unstable in the repository, do you want --any or --rev)
+  (2 other orphan in the repository, do you want --any or --rev)
   [2]
 
 
@@ -991,6 +991,19 @@
   working directory is now at d952e93add6f
   $ ls .hg/bookmarks*
   .hg/bookmarks
+  $ hg log -G
+  @  11	: a2 - test
+  |
+  o  10	testbookmark: a1__ - test
+  |
+  | o  9	: a3 - test
+  | |
+  | x  8	: a2 - test
+  | |
+  | x  7	: a1_ - test
+  |/
+  o  0	: a0 - test
+  
 
 Possibility to select what trouble to solve first, asking for bumped before
 divergent
@@ -1050,7 +1063,7 @@
   |/
   o  0	: a0 - test
   
-  $ hg evolve -r 12 --bumped
+  $ hg evolve -r 12 --phasedivergent
   recreate:[12] add new file bumped
   atop:[11] a2
   computing new diff
@@ -1060,15 +1073,27 @@
   move:[9] a3
   atop:[13] bumped update to d952e93add6f:
   working directory is now at cce26b684bfe
+  $ glog
+  @  14:cce26b684bfe@default(draft) a3
+  |
+  o  13:f15d32934071@default(draft) bumped update to d952e93add6f:
+  |
+  o  11:d952e93add6f@mybranch(public) a2
+  |
+  o  10:9f8b83c2e7f3@default(public) a1__
+  |
+  o  0:07c1c36d9ef0@default(public) a0
+  
+
 Check that we can resolve troubles in a revset with more than one commit
-  $ hg up 14 -C
+  $ hg up cce26b684bfe -C
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ mkcommit gg
-  $ hg up 14 
+  $ hg up cce26b684bfe
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ mkcommit gh
   created new head
-  $ hg up 14 
+  $ hg up cce26b684bfe
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ printf "newline\nnewline\n" >> a
   $ hg log -G
@@ -1111,11 +1136,11 @@
   set of specified revisions is empty
   [1]
 
-  $ hg evolve --rev "14::" --bumped
-  no bumped changesets in specified revisions
-  (do you want to use --unstable)
+  $ hg evolve --rev "14::" --phasedivergent
+  no phasedivergent changesets in specified revisions
+  (do you want to use --orphan)
   [2]
-  $ hg evolve --rev "14::" --unstable
+  $ hg evolve --rev "14::" --orphan
   move:[15] add gg
   atop:[18] a3
   move:[16] add gh
@@ -1313,7 +1338,7 @@
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg evolve --all
   nothing to evolve on current working copy parent
-  (2 other unstable in the repository, do you want --any or --rev)
+  (2 other orphan in the repository, do you want --any or --rev)
   [2]
   $ hg evolve --all --any
   move:[22] add j2
@@ -1409,7 +1434,7 @@
   $ hg add oo pp
   $ hg commit -m "oo+pp"
   $ mkcommit uu
-  $ hg up 30
+  $ hg up 68330ac625b8
   0 files updated, 0 files merged, 3 files removed, 0 files unresolved
   $ printf "oo" > oo;
   $ hg add oo
@@ -1461,7 +1486,30 @@
   $ hg add newlyadded
   $ hg commit -m "will cause conflict at evolve"
 
-  $ hg update -q 37
+  $ glog -r "edc3c9de504e::"
+  @  39:02e943732647@default(draft) will cause conflict at evolve
+  |
+  o  38:f8e30e9317aa@default(draft) will be evolved safely
+  |
+  o  37:36030b147271@default(draft) will be amended
+  |
+  o  36:43c3f5ef149f@default(draft) add uu
+  |
+  o  35:7a555adf2b4a@default(draft) _pp
+  |
+  o  34:2be4d2d5bf34@default(draft) _oo
+  |
+  | o  31:580886d07058@default(draft) add gg
+  | |
+  o |  30:68330ac625b8@default(draft) add unstableifparentisfolded
+  |/
+  | o  20:e02107f98737@default(draft) add gh
+  |/
+  o  18:edc3c9de504e@default(draft) a3
+  |
+  ~
+
+  $ hg update -q 36030b147271
   $ echo "amended" > newfile
   $ hg amend -m "amended"
   2 new unstable changesets
--- a/tests/test-exchange-obsmarkers-case-A1.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A1.t	Wed Sep 27 01:12:47 2017 +0200
@@ -61,7 +61,7 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -88,7 +88,7 @@
   # testing echange of "A" (f5bc6836db60)
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "A" from main to pushdest
@@ -101,9 +101,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "f5bc6836db60" from main into pulldest
   pulling from main
@@ -116,11 +116,11 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
 
 Variant b: push
 ---------------
@@ -129,7 +129,7 @@
   ## Running testcase A.1.1.b
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing from main to pushdest
@@ -142,9 +142,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling from main into pulldest
   pulling from main
@@ -157,11 +157,11 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
 
 A.1.2 pushing multiple changesets into a single head
 ====================================================
@@ -212,7 +212,7 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -242,7 +242,7 @@
   # testing echange of "B" (f6fbb35d8ac9)
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "B" from main to pushdest
@@ -255,9 +255,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "f6fbb35d8ac9" from main into pulldest
   pulling from main
@@ -270,11 +270,11 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
 
 Variant b: push
 ---------------
@@ -283,7 +283,7 @@
   ## Running testcase A.1.2.b
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing from main to pushdest
@@ -296,9 +296,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling from main into pulldest
   pulling from main
@@ -311,8 +311,8 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
--- a/tests/test-exchange-obsmarkers-case-A2.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A2.t	Wed Sep 27 01:12:47 2017 +0200
@@ -71,8 +71,8 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -97,8 +97,8 @@
   # testing echange of "A" (f5bc6836db60)
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "A" from main to pushdest
@@ -111,10 +111,10 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "f5bc6836db60" from main into pulldest
   pulling from main
@@ -127,11 +127,11 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
+  bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 35b1839966785d5703a01607229eea932db42f87 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
 
   $ cd ..
--- a/tests/test-exchange-obsmarkers-case-A3.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A3.t	Wed Sep 27 01:12:47 2017 +0200
@@ -88,8 +88,8 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -116,8 +116,8 @@
   # testing echange of "A1" (e5ea8f9c7314)
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "A1" from main to pushdest
@@ -130,10 +130,10 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "e5ea8f9c7314" from main into pulldest
   pulling from main
@@ -146,12 +146,12 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
 
 other variant: changeset known in remote
 ----------------------------------------
@@ -189,8 +189,8 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -230,8 +230,8 @@
   # testing echange of "A1" (e5ea8f9c7314)
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "A1" from main to pushdest
@@ -244,10 +244,10 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "e5ea8f9c7314" from main into pulldest
   pulling from main
@@ -261,9 +261,9 @@
   1 new unstable changesets
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
--- a/tests/test-exchange-obsmarkers-case-A4.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A4.t	Wed Sep 27 01:12:47 2017 +0200
@@ -76,8 +76,8 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -105,8 +105,8 @@
   # testing echange of "B" (06055a7959d4)
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "B" from main to pushdest
@@ -119,10 +119,10 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "06055a7959d4" from main into pulldest
   pulling from main
@@ -135,9 +135,9 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
--- a/tests/test-exchange-obsmarkers-case-A5.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A5.t	Wed Sep 27 01:12:47 2017 +0200
@@ -81,9 +81,9 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -110,9 +110,9 @@
   # testing echange of "B1" (f6298a8ac3a4)
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "B1" from main to pushdest
@@ -125,11 +125,11 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "f6298a8ac3a4" from main into pulldest
   pulling from main
@@ -142,10 +142,10 @@
   (run 'hg update' to get a working copy)
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f 8c0a98c8372212c6efde4bfdcef006f27ff759d3 0 (*) {'user': 'test'} (glob)
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  6e72f0a95b5e01a7504743aa941f69cb1fbef8b0 f6298a8ac3a4b78bbeae5f1d3dc5bc3c3812f0f3 0 (*) {'user': 'test'} (glob)
--- a/tests/test-exchange-obsmarkers-case-A6.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A6.t	Wed Sep 27 01:12:47 2017 +0200
@@ -74,7 +74,7 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -100,7 +100,7 @@
   # testing echange of "A1" (e5ea8f9c7314)
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "A1" from main to pushdest
@@ -110,9 +110,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling "e5ea8f9c7314" from main into pulldest
   pulling from main
@@ -120,11 +120,11 @@
   1 new obsolescence markers
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
 
 Actual Test (bare push version)
 -------------------------------
@@ -133,7 +133,7 @@
   ## Running testcase A.6.b
   ## initial state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing from main to pushdest
@@ -143,9 +143,9 @@
   remote: 1 new obsolescence markers
   ## post push state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
   ## pulling from main into pulldest
   pulling from main
@@ -154,8 +154,8 @@
   1 new obsolescence markers
   ## post pull state
   # obstore: main
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
   # obstore: pulldest
-  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  28b51eb45704506b5c603decd6bf7ac5e0f6a52f e5ea8f9c73143125d36658e90ef70c6d2027a5b7 0 (*) {'user': 'test'} (glob)
--- a/tests/test-exchange-obsmarkers-case-A7.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-exchange-obsmarkers-case-A7.t	Wed Sep 27 01:12:47 2017 +0200
@@ -59,7 +59,7 @@
   $ inspect_obsmarkers
   obsstore content
   ================
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   obshashtree
   ===========
   a9bdc8b26820b1b87d585b82eb0ceb4a2ecdbc04 0000000000000000000000000000000000000000
@@ -81,7 +81,7 @@
   # testing echange of "O" (a9bdc8b26820)
   ## initial state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pushing "O" from main to pushdest
@@ -90,7 +90,7 @@
   no changes found
   ## post push state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
   ## pulling "a9bdc8b26820" from main into pulldest
@@ -98,6 +98,6 @@
   no changes found
   ## post pull state
   # obstore: main
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa f5bc6836db60e308a17ba08bf050154ba9c4fad7 0 (*) {'user': 'test'} (glob)
   # obstore: pushdest
   # obstore: pulldest
--- a/tests/test-inhibit.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-inhibit.t	Wed Sep 27 01:12:47 2017 +0200
@@ -159,6 +159,7 @@
   o  0:54ccbc537fc2 add cA
   
   $ hg phase --public 7
+  1 new bumped changesets
   $ hg strip 9
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory now at cf5c4f4554ce
@@ -846,7 +847,7 @@
   created new head
   $ mkcommit Dp
   $ mkcommit Do
-  $ hg log -G -r "25::"
+  $ hg log -G -r "71eb4f100663::"
   @  30:b517facce1ef add Do
   |
   o  29:c5a47ab27c2e add Dp
@@ -858,14 +859,14 @@
   o  25:71eb4f100663 add pk
   |
   ~
-  $ hg prune 28 -s 27
+  $ hg prune 8c1c2edbaf1b -s 1192fa9fbc68
   1 changesets pruned
-  $ hg up 25
+  $ hg up 71eb4f100663
   0 files updated, 0 files merged, 3 files removed, 0 files unresolved
-  $ hg rebase -r "28 + 29" --keep -d 27 --config experimental.rebaseskipobsolete=True
+  $ hg rebase -r "8c1c2edbaf1b + c5a47ab27c2e" --keep -d 1192fa9fbc68 --config experimental.rebaseskipobsolete=True
   note: not rebasing 28:8c1c2edbaf1b "add Dl", already in destination as 27:1192fa9fbc68 "add Dk"
   rebasing 29:c5a47ab27c2e "add Dp"
-  $ hg log -G  -r "25::"
+  $ hg log -G  -r "71eb4f100663::"
   o  31:7d8affb1f604 add Dp
   |
   | o  30:b517facce1ef add Do
@@ -883,11 +884,11 @@
 Rebase the same stack in full on the destination, we expect it to disappear
 and only see the top revision added to destination. We don\'t expect 29 to be
 skipped as we used --keep before.
-  $ hg rebase -s 28 -d 27 --config experimental.rebaseskipobsolete=True
+  $ hg rebase -s 8c1c2edbaf1b -d 1192fa9fbc68 --config experimental.rebaseskipobsolete=True
   note: not rebasing 28:8c1c2edbaf1b "add Dl", already in destination as 27:1192fa9fbc68 "add Dk"
   rebasing 29:c5a47ab27c2e "add Dp"
   rebasing 30:b517facce1ef "add Do"
-  $ hg log -G  -r "25::"
+  $ hg log -G  -r "71eb4f100663::"
   o  32:1d43fff9e26f add Do
   |
   o  31:7d8affb1f604 add Dp
--- a/tests/test-obsolete.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-obsolete.t	Wed Sep 27 01:12:47 2017 +0200
@@ -694,11 +694,11 @@
   [2]
   $ hg olog
   @  0d3f46688ccc (3) add obsol_c
-  |    rewritten(parent) by test (*) as 2033b4e49474 (glob)
-  |    rewritten by test (*) as 725c380fe99b (glob)
+  |    rewritten(parent) as 2033b4e49474 by test (*) (glob)
+  |    rewritten as 725c380fe99b by test (*) (glob)
   |
   x  4538525df7e2 (2) add c
-       rewritten by test (*) as 0d3f46688ccc (glob)
+       rewritten as 0d3f46688ccc by test (*) (glob)
   
 
 Check import reports new unstable changeset:
@@ -706,7 +706,7 @@
   $ hg up --hidden 2
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   working directory parent is obsolete! (4538525df7e2)
-  (4538525df7e2 has diverged, use 'hg evolve --list --divergent' to resolve the issue)
+  (4538525df7e2 has diverged, use 'hg evolve --list --contentdivergent' to resolve the issue)
   $ hg export 9468a5f5d8b2 | hg import -
   applying patch from stdin
   1 new unstable changesets
--- a/tests/test-sharing.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-sharing.t	Wed Sep 27 01:12:47 2017 +0200
@@ -507,7 +507,7 @@
   7:e3f99ce9d9cd  draft  fix bug 24 (v2 by alice)
 
 Use evolve to fix the divergence.
-  $ HGMERGE=internal:other hg evolve --divergent
+  $ HGMERGE=internal:other hg evolve --contentdivergent
   merge:[6] fix bug 24 (v2 by bob)
   with: [7] fix bug 24 (v2 by alice)
   base: [4] fix bug 24 (v1)
--- a/tests/test-split.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-split.t	Wed Sep 27 01:12:47 2017 +0200
@@ -409,10 +409,12 @@
   $ echo "[extensions]" >> $HGRCPATH
   $ echo "topic=$(echo $(dirname $TESTDIR))/hgext3rd/topic/" >> $HGRCPATH
   $ hg topic mytopic
+  marked working directory as topic: mytopic
   $ echo babar > babar
   $ echo celeste > celeste
   $ hg add babar celeste
   $ hg commit -m "Works on mytopic" babar celeste --user victor
+  active topic 'mytopic' grew its first changeset
   $ hg log -r . 
   changeset:   21:26f72cfaf036
   branch:      new-branch
--- a/tests/test-stabilize-conflict.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-stabilize-conflict.t	Wed Sep 27 01:12:47 2017 +0200
@@ -161,7 +161,7 @@
   
 (fix the conflict and continue)
 
-  $ hg revert -r 5 --all
+  $ hg revert -r 71c18f70c34f --all
   reverting babar
   $ safesed 's/dix/ten/' babar
   $ hg resolve --all -m
--- a/tests/test-stabilize-order.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-stabilize-order.t	Wed Sep 27 01:12:47 2017 +0200
@@ -89,7 +89,7 @@
 
 Test stabilizing a descendant predecessor's child
 
-  $ hg up 7
+  $ hg up -r 005fe5914f78
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg debugobsolete > successors.old
   $ hg evolve -v
@@ -133,7 +133,7 @@
 
 Test behavior with --any
 
-  $ hg up 8
+  $ hg up 81b8bbcd5892
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo b >> b
   $ hg amend
@@ -149,11 +149,11 @@
   |
   o  0:c471ef929e6a@default(draft) addroot
   
-  $ hg up 9
+  $ hg up 0f691739f917
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg evolve -v
   nothing to evolve on current working copy parent
-  (1 other unstable in the repository, do you want --any or --rev)
+  (1 other orphan in the repository, do you want --any or --rev)
   [2]
   $ hg evolve --any -v
   move:[9] addc
@@ -179,7 +179,7 @@
   o  0:c471ef929e6a@default(draft) addroot
   
   $ hg evolve --any -v
-  no unstable changesets to evolve
+  no orphan changesets to evolve
   [1]
 
 Ambiguous evolution
--- a/tests/test-stabilize-result.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-stabilize-result.t	Wed Sep 27 01:12:47 2017 +0200
@@ -129,7 +129,7 @@
 
 Get a successors of 8 on it
 
-  $ hg grab 8
+  $ hg grab 1cf0aacfd363
   rebasing 8:1cf0aacfd363 "newer a"
   ? files updated, 0 files merged, 0 files removed, 0 files unresolved (glob)
 
@@ -140,7 +140,7 @@
 
 Make precursors public
 
-  $ hg phase --hidden --public 8
+  $ hg phase --hidden --public 1cf0aacfd363
   1 new bumped changesets
   $ glog
   @  12:(73b15c7566e9|d5c7ef82d003)@default\(draft\) bk:\[\] newer a (re)
@@ -156,20 +156,20 @@
 
 Stabilize!
 
-  $ hg evolve --any --dry-run --bumped
+  $ hg evolve --any --dry-run --phasedivergent
   recreate:[12] newer a
   atop:[8] newer a
   hg rebase --rev (73b15c7566e9|d5c7ef82d003) --dest 66719795a494; (re)
   hg update 1cf0aacfd363;
   hg revert --all --rev (73b15c7566e9|d5c7ef82d003); (re)
   hg commit --msg "bumped update to %s" (no-eol)
-  $ hg evolve --any --confirm --bumped
+  $ hg evolve --any --confirm --phasedivergent
   recreate:[12] newer a
   atop:[8] newer a
   perform evolve? [Ny] n
   abort: evolve aborted by user
   [255]
-  $ echo y | hg evolve --any --confirm --config ui.interactive=True --bumped
+  $ echo y | hg evolve --any --confirm --config ui.interactive=True --phasedivergent
   recreate:[12] newer a
   atop:[8] newer a
   perform evolve? [Ny] y
@@ -193,7 +193,7 @@
 ===============================================
 
   $ rm a.orig
-  $ hg up 9
+  $ hg up 7bc2f5967f5e
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cat << EOF >> a
   > flore
@@ -219,7 +219,7 @@
   
   $ echo 'babar' >> a
   $ hg amend
-  $ hg up --hidden 15
+  $ hg up --hidden 3932c176bbaa
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   working directory parent is obsolete! (3932c176bbaa)
   (use 'hg evolve' to update to its successor: d2f173e25686)
@@ -247,14 +247,14 @@
 
 Stabilize it
 
-  $ hg evolve -qn --confirm --divergent
+  $ hg evolve -qn --confirm --contentdivergent
   merge:[19] More addition
   with: [17] More addition
   base: [15] More addition
   perform evolve? [Ny] n
   abort: evolve aborted by user
   [255]
-  $ echo y | hg evolve -qn --confirm --config ui.interactive=True --divergent
+  $ echo y | hg evolve -qn --confirm --config ui.interactive=True --contentdivergent
   merge:[19] More addition
   with: [17] More addition
   base: [15] More addition
@@ -265,7 +265,7 @@
   hg up -C 3932c176bbaa &&
   hg revert --all --rev tip &&
   hg commit -m "`hg log -r eacc9c8240fe --template={desc}`";
-  $ hg evolve -v --divergent
+  $ hg evolve -v --contentdivergent
   merge:[19] More addition
   with: [17] More addition
   base: [15] More addition
@@ -332,7 +332,7 @@
 Check conflict during divergence resolution
 -------------------------------------------------
 
-  $ hg up --hidden 15
+  $ hg up --hidden 3932c176bbaa
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   working directory parent is obsolete! (3932c176bbaa)
   (use 'hg evolve' to update to its successor: f344982e63c4)
@@ -344,14 +344,14 @@
   $ hg phase 'divergent()'
   21: draft
   24: draft
-  $ hg evolve -qn --divergent
+  $ hg evolve -qn --contentdivergent
   hg update -c 0b336205a5d0 &&
   hg merge f344982e63c4 &&
   hg commit -m "auto merge resolving conflict between 0b336205a5d0 and f344982e63c4"&&
   hg up -C 3932c176bbaa &&
   hg revert --all --rev tip &&
   hg commit -m "`hg log -r 0b336205a5d0 --template={desc}`";
-  $ hg evolve --divergent
+  $ hg evolve --contentdivergent
   merge:[24] More addition (2)
   with: [21] More addition
   base: [15] More addition
--- a/tests/test-stack-branch.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-stack-branch.t	Wed Sep 27 01:12:47 2017 +0200
@@ -55,7 +55,7 @@
   $ hg up other
   0 files updated, 0 files merged, 4 files removed, 0 files unresolved
   $ hg stack
-  ### branch: other
+  ### target: other (branch)
   b2@ c_b (current)
   b1: c_a
   $ hg phase --public 'branch("other")'
@@ -70,14 +70,14 @@
   $ hg branch
   foo
   $ hg stack
-  ### branch: foo
+  ### target: foo (branch)
   b4@ c_f (current)
   b3: c_e
   b2: c_d
   b1: c_c
   b0^ c_b (base)
   $ hg stack -v
-  ### branch: foo
+  ### target: foo (branch)
   b4(913c298d8b0a)@ c_f (current)
   b3(4f2a69f6d380): c_e
   b2(f61adbacd17a): c_d
@@ -125,7 +125,7 @@
   o  0 other {} public c_a
   
   $ hg stack
-  ### branch: foo
+  ### target: foo (branch)
   b4$ c_f (unstable)
   b3$ c_e (unstable)
   b2@ c_d (current)
@@ -134,7 +134,7 @@
   $ hg up b3
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg stack
-  ### branch: foo
+  ### target: foo (branch)
   b4$ c_f (unstable)
   b3$ c_e (current unstable)
   b2: c_d
@@ -205,7 +205,7 @@
 Test output
 
   $ hg stack
-  ### branch: foo (2 heads)
+  ### target: foo (branch) (2 heads)
   b6: c_f
   b5: c_e
   b2^ c_d (base)
@@ -248,7 +248,7 @@
   
 
   $ hg stack
-  ### branch: foo (2 heads)
+  ### target: foo (branch) (2 heads)
   b6$ c_f (unstable)
   b5$ c_e (unstable)
   b2^ c_D (base)
@@ -261,8 +261,28 @@
 Check that stack doesn't show draft changesets on a branch
 ----------------------------------------------------------
 
+  $ hg log --graph
+  o  15 foo {} draft c_h
+  |
+  o  14 foo {} draft c_g
+  |
+  @  13 foo {} draft c_D
+  |
+  | o  9 foo {} draft c_f
+  | |
+  | o  8 foo {} draft c_e
+  | |
+  | x  7 foo {} draft c_d
+  |/
+  o  2 foo {} draft c_c
+  |
+  o  1 other {} public c_b
+  |
+  o  0 other {} public c_a
+  
+
   $ hg stack
-  ### branch: foo (2 heads)
+  ### target: foo (branch) (2 heads)
   b6$ c_f (unstable)
   b5$ c_e (unstable)
   b2^ c_D (base)
@@ -273,7 +293,7 @@
   b0^ c_b (base)
   $ hg phase --public b1
   $ hg stack
-  ### branch: foo (2 heads)
+  ### target: foo (branch) (2 heads)
   b5$ c_f (unstable)
   b4$ c_e (unstable)
   b1^ c_D (base)
@@ -288,7 +308,7 @@
   $ hg topic --rev b4::b5 sometopic
   changed topic on 2 changes
   $ hg stack
-  ### branch: foo
+  ### target: foo (branch)
   b3: c_h
   b2: c_g
   b1@ c_D (current)
--- a/tests/test-topic-dest.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-dest.t	Wed Sep 27 01:12:47 2017 +0200
@@ -28,6 +28,7 @@
   $ echo babar >> jungle
   $ hg add jungle
   $ hg ci -t elephant -m babar
+  active topic 'elephant' grew its first changeset
 
   $ hg log -G
   @  4 (elephant) babar
@@ -53,6 +54,7 @@
   $ echo zephir >> jungle
   $ hg add jungle
   $ hg ci -t monkey -m zephir
+  active topic 'monkey' grew its first changeset
   $ hg log -G
   @  5 (monkey) zephir
   |
@@ -450,6 +452,7 @@
   $ hg up 'p1(roots(topic(elephant)))'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic elephant
+  marked working directory as topic: elephant
   $ hg up
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg log -G
--- a/tests/test-topic-fold.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-fold.t	Wed Sep 27 01:12:47 2017 +0200
@@ -37,7 +37,9 @@
   $ cd testfold
   $ mkcommit ROOT
   $ hg topic myfeature
+  marked working directory as topic: myfeature
   $ mkcommit feature1
+  active topic 'myfeature' grew its first changeset
   $ mkcommit feature2
   $ logtopic
   @  2:d76a6166b18c835be9a487c5e21c7d260f0a1676
@@ -51,7 +53,7 @@
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg stack
   ### topic: myfeature
-  ### branch: default
+  ### target: default (branch)
   t1@ folded (current)
   t0^ add ROOT (base)
   $ logtopic
@@ -77,7 +79,9 @@
   $ mkcommit feature3
   created new head
   $ hg topic myotherfeature
+  marked working directory as topic: myotherfeature
   $ mkcommit feature4
+  active topic 'myotherfeature' grew its first changeset
   $ logtopic
   @  5:5ded4d6d578c37f339b0716de2e46e12ece7cbde
   |  topics: myotherfeature
@@ -88,7 +92,9 @@
   o  0:3e7df3b3b17c6deb4a1c70e790782fdf17af96a7
      topics:
   $ hg fold --exact -r "(tip~1)::" -m "folded 2"
+  active topic 'myotherfeature' is now empty
   2 changesets folded
+  clearing empty topic "myotherfeature"
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ logtopic
   @  6:03da8f7238e9a4d708d6b8af402c91c68f271477
--- a/tests/test-topic-push-concurrent-on.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-push-concurrent-on.t	Wed Sep 27 01:12:47 2017 +0200
@@ -130,9 +130,11 @@
   $ hg up -r 'desc(CA)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic babar
+  marked working directory as topic: babar
   $ echo aaa > ddd
   $ hg add ddd
   $ hg commit -m 'CD'
+  active topic 'babar' grew its first changeset
   $ hg log -G # keep track of phase because I saw some strange bug during developement
   @  5 default babar draft CD
   |
@@ -186,9 +188,11 @@
   $ hg up -r 'desc(CA)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic celeste
+  marked working directory as topic: celeste
   $ echo aaa > eee
   $ hg add eee
   $ hg commit -m 'CE'
+  active topic 'celeste' grew its first changeset
   $ hg log -G # keep track of phase because I saw some strange bug during developement
   @  6 default celeste draft CE
   |
@@ -274,6 +278,7 @@
   $ hg up 'desc(CB)'
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic babar
+  marked working directory as topic: babar
   $ echo aaa > fff
   $ hg add fff
   $ hg commit -m 'CF'
@@ -379,13 +384,17 @@
   $ echo aaa > aaa
   $ hg add aaa
   $ hg topic topicA
+  marked working directory as topic: topicA
   $ hg commit -m 'CA'
+  active topic 'topicA' grew its first changeset
   $ hg up 'desc(CBASE)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo aaa > bbb
   $ hg add bbb
   $ hg topic topicB
+  marked working directory as topic: topicB
   $ hg commit -m 'CB'
+  active topic 'topicB' grew its first changeset
   $ cd ..
   $ hg push -R repoA repoB
   pushing to repoB
--- a/tests/test-topic-push.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-push.t	Wed Sep 27 01:12:47 2017 +0200
@@ -126,9 +126,11 @@
   $ hg up -r 'desc(CA)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic babar
+  marked working directory as topic: babar
   $ echo aaa > ddd
   $ hg add ddd
   $ hg commit -m 'CD'
+  active topic 'babar' grew its first changeset
   $ hg log -G # keep track of phase because I saw some strange bug during developement
   @  5 default babar draft CD
   |
@@ -157,6 +159,61 @@
   |/
   o  0 default  public CA
   
+push --topic
+
+  $ hg log -G -R $TESTTMP/draft
+  o  3 default babar draft CD
+  |
+  | o  2 mountain  public CC
+  |/
+  | o  1 default  public CB
+  |/
+  o  0 default  public CA
+  
+  $ echo bbb >> aaa
+  $ hg commit -m "C'A"
+  $ hg up 1
+  2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg topic --clear
+  $ echo bbb >> bbb
+  $ hg commit -m "C'B"
+  $ hg log -G
+  @  7 default  draft C'B
+  |
+  | o  6 default babar draft C'A
+  | |
+  | o  5 default babar draft CD
+  | |
+  | | o  4 mountain  public CC
+  | |/
+  o |  1 default  public CB
+  |/
+  o  0 default  public CA
+  
+  $ hg outgoing draft --topic babar
+  comparing with $TESTTMP/draft
+  searching for changes
+  6 default babar draft C'A
+  $ hg push draft --topic babar
+  pushing to $TESTTMP/draft
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  $ hg log -G -R $TESTTMP/draft
+  o  4 default babar draft C'A
+  |
+  o  3 default babar draft CD
+  |
+  | o  2 mountain  public CC
+  |/
+  | o  1 default  public CB
+  |/
+  o  0 default  public CA
+  
+  $ hg strip --hidden --config extensions.strip= --no-backup -r 6: --quiet
+  $ hg strip --hidden --config extensions.strip= -R $TESTTMP/draft --no-backup -r 4: --quiet
 
 Pushing a new topic to a publishing server should be seen as a new head
 
@@ -182,9 +239,11 @@
   $ hg up -r 'desc(CA)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic celeste
+  marked working directory as topic: celeste
   $ echo aaa > eee
   $ hg add eee
   $ hg commit -m 'CE'
+  active topic 'celeste' grew its first changeset
   $ hg log -G # keep track of phase because I saw some strange bug during developement
   @  6 default celeste draft CE
   |
@@ -270,6 +329,7 @@
   $ hg up 'desc(CB)'
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic babar
+  marked working directory as topic: babar
   $ echo aaa > fff
   $ hg add fff
   $ hg commit -m 'CF'
@@ -375,13 +435,17 @@
   $ echo aaa > aaa
   $ hg add aaa
   $ hg topic topicA
+  marked working directory as topic: topicA
   $ hg commit -m 'CA'
+  active topic 'topicA' grew its first changeset
   $ hg up 'desc(CBASE)'
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo aaa > bbb
   $ hg add bbb
   $ hg topic topicB
+  marked working directory as topic: topicB
   $ hg commit -m 'CB'
+  active topic 'topicB' grew its first changeset
   $ cd ..
   $ hg push -R repoA repoB
   pushing to repoB
--- a/tests/test-topic-rebase.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-rebase.t	Wed Sep 27 01:12:47 2017 +0200
@@ -40,10 +40,12 @@
 
 Work on myfeature
   $ hg topic myfeature
+  marked working directory as topic: myfeature
   $ mkcommit feature1
+  active topic 'myfeature' grew its first changeset
   $ hg stack
   ### topic: myfeature
-  ### branch: default
+  ### target: default (branch)
   t1@ add feature1 (current)
   t0^ add ROOT (base)
   $ logtopic
@@ -73,7 +75,7 @@
   switching to topic myfeature
   $ hg stack
   ### topic: myfeature
-  ### branch: default
+  ### target: default (branch)
   t1@ add feature1 (current)
   t0^ add default (base)
   $ logtopic
@@ -87,7 +89,7 @@
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg stack
   ### topic: myfeature
-  ### branch: default
+  ### target: default (branch)
   t1@ add feature1 (current)
   t0^ add default (base)
 
@@ -102,8 +104,10 @@
 
 Update the common file in a topic
   $ hg topic myotherfeature
+  marked working directory as topic: myotherfeature
   $ echo "B" >> file
   $ hg commit -m "myotherfeature1"
+  active topic 'myotherfeature' grew its first changeset
 
 Update the common file in default
   $ hg update --rev default
@@ -149,13 +153,13 @@
      topics:
   $ hg stack
   ### topic: myotherfeature
-  ### branch: default
+  ### target: default (branch)
   t1@ myotherfeature1 (current)
   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
+  ### target: default (branch)
   t1@ myotherfeature1 (current)
   t0^ default3 (base)
--- a/tests/test-topic-shelve.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-shelve.t	Wed Sep 27 01:12:47 2017 +0200
@@ -13,16 +13,18 @@
   $ touch a
   $ echo "Hello" >> a
   $ hg topic "testing-shelve"
+  marked working directory as topic: testing-shelve
   $ hg topic
    * testing-shelve
   $ hg ci -m "First commit" -A
   adding a
+  active topic 'testing-shelve' grew its first changeset
   $ hg topic
    * testing-shelve
   $ echo " World" >> a
   $ hg stack
   ### topic: testing-shelve
-  ### branch: default
+  ### target: default (branch)
   t1@ First commit (current)
 
 shelve test
@@ -35,7 +37,7 @@
    * testing-shelve
   $ hg stack
   ### topic: testing-shelve
-  ### branch: default
+  ### target: default (branch)
   t1@ First commit (current)
 
 unshelve test
@@ -46,5 +48,5 @@
    * testing-shelve
   $ hg stack
   ### topic: testing-shelve
-  ### branch: default
+  ### target: default (branch)
   t1@ First commit (current)
--- a/tests/test-topic-stack-data.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-stack-data.t	Wed Sep 27 01:12:47 2017 +0200
@@ -54,7 +54,9 @@
   $ hg up 'desc(base_c)'
   2 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ hg topic baz
+  marked working directory as topic: baz
   $ mkcommit baz_a
+  active topic 'baz' grew its first changeset
   $ mkcommit baz_b
 
 A simple topic with unstability
@@ -62,7 +64,9 @@
   $ hg up 'desc(base_d)'
   1 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ hg topic fuz
+  marked working directory as topic: fuz
   $ mkcommit fuz_a
+  active topic 'fuz' grew its first changeset
   $ mkcommit fuz_b
   $ mkcommit fuz_c
   $ hg up 'desc(fuz_a)'
@@ -74,7 +78,9 @@
   $ hg up 'desc(base_e)'
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ hg topic bar
+  marked working directory as topic: bar
   $ mkcommit bar_a
+  active topic 'bar' grew its first changeset
   $ mkcommit bar_b
   $ mkcommit bar_c
   $ hg up 'desc(bar_b)'
@@ -90,7 +96,9 @@
   $ hg up 'desc(lake_a)'
   1 files updated, 0 files merged, 7 files removed, 0 files unresolved
   $ hg topic foo
+  marked working directory as topic: foo
   $ mkcommit foo_a
+  active topic 'foo' grew its first changeset
   $ mkcommit foo_b
 
 Summary
@@ -175,7 +183,7 @@
   $ hg topic --verbose
      bar (on branch: default, 5 changesets, 1 troubled, 2 heads)
      baz (on branch: default, 2 changesets, 2 behind)
-   * foo (on branch: lake, 2 changesets, ambiguous destination)
+   * foo (on branch: lake, 2 changesets, ambiguous destination: branch 'lake' has 2 heads)
      fuz (on branch: default, 3 changesets, 2 troubled, 1 behind)
 
 json
@@ -221,7 +229,7 @@
    },
    {
     "active": true,
-    "behinderror": "ambiguous destination",
+    "behinderror": "ambiguous destination: branch 'lake' has 2 heads",
     "branches+": "lake",
     "changesetcount": 2,
     "topic": "foo"
@@ -241,7 +249,7 @@
 
   $ hg stack bar
   ### topic: bar (2 heads)
-  ### branch: default
+  ### target: default (branch)
   t5: add bar_c
   t2^ add bar_b (base)
   t4$ add bar_e (unstable)
@@ -251,7 +259,7 @@
   t0^ add base_e (base)
   $ hg stack bar -v
   ### topic: bar (2 heads)
-  ### branch: default
+  ### target: default (branch)
   t5(9cbadf11b44d): add bar_c
   t2(e555c7e8c767)^ add bar_b (base)
   t4(a920412b5a05)$ add bar_e (unstable)
@@ -261,19 +269,19 @@
   t0(92f489a6251f)^ add base_e (base)
   $ hg stack baz
   ### topic: baz
-  ### branch: default, 2 behind
+  ### target: default (branch), 2 behind
   t2: add baz_b
   t1: add baz_a
   t0^ add base_c (base)
   $ hg stack foo
   ### topic: foo
-  ### branch: lake, ambigious rebase destination
+  ### target: lake (branch), ambigious rebase destination - branch 'lake' has 2 heads
   t2@ add foo_b (current)
   t1: add foo_a
   t0^ add lake_a (base)
   $ hg stack fuz
   ### topic: fuz
-  ### branch: default, 1 behind
+  ### target: default (branch), 1 behind
   t3$ add fuz_c (unstable)
   t2$ add fuz_b (unstable)
   t1: fuz1_a
--- a/tests/test-topic-stack.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-stack.t	Wed Sep 27 01:12:47 2017 +0200
@@ -15,9 +15,11 @@
   $ hg init main
   $ cd main
   $ hg topic other
+  marked working directory as topic: other
   $ echo aaa > aaa
   $ hg add aaa
   $ hg commit -m c_a
+  active topic 'other' grew its first changeset
   $ echo aaa > bbb
   $ hg add bbb
   $ hg commit -m c_b
@@ -25,6 +27,7 @@
   $ echo aaa > ccc
   $ hg add ccc
   $ hg commit -m c_c
+  active topic 'foo' grew its first changeset
   $ echo aaa > ddd
   $ hg add ddd
   $ hg commit -m c_d
@@ -56,10 +59,23 @@
   0 files updated, 0 files merged, 4 files removed, 0 files unresolved
   $ hg topic --list
   ### topic: other
-  ### branch: default
+  ### target: default (branch)
   t2@ c_b (current)
   t1: c_a
   $ hg phase --public 'topic("other")'
+  active topic 'other' is now empty
+
+After changing the phase of all the changesets in "other" to public, the topic should still be active, but is empty. We should be better at informating the user about it and displaying good data in this case.
+
+  $ hg topic
+     foo
+   * other
+  $ hg stack
+  ### topic: other
+  ### target: default (branch)
+  (stack is empty)
+  t0^ c_b (base)
+
   $ hg up foo
   switching to topic foo
   4 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -73,7 +89,7 @@
    * foo
   $ hg stack
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4@ c_f (current)
   t3: c_e
   t2: c_d
@@ -81,7 +97,7 @@
   t0^ c_b (base)
   $ hg stack -v
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4(6559e6d93aea)@ c_f (current)
   t3(0f9ac936c87d): c_e
   t2(e629654d7050): c_d
@@ -195,7 +211,7 @@
    * foo
   $ hg stack
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4@ c_f (current)
   t3: c_e
   t2: c_d
@@ -205,7 +221,7 @@
    * foo
   $ hg stack --config ui.strict=true
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4@ c_f (current)
   t3: c_e
   t2: c_d
@@ -216,7 +232,9 @@
 
   $ hg topic --clear
   $ hg stack
-  ### branch: 
+  ### target: default (branch)
+  (stack is empty)
+  b0^ c_f (base)
 
 Test "t#" reference
 -------------------
@@ -226,6 +244,7 @@
   abort: cannot resolve "t2": no active topic
   [255]
   $ hg topic foo
+  marked working directory as topic: foo
   $ hg up t42
   abort: cannot resolve "t42": topic "foo" has only 4 changesets
   [255]
@@ -262,7 +281,7 @@
   
   $ hg topic --list
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4$ c_f (unstable)
   t3$ c_e (unstable)
   t2@ c_d (current)
@@ -272,7 +291,7 @@
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg topic --list
   ### topic: foo
-  ### branch: default
+  ### target: default (branch)
   t4$ c_f (unstable)
   t3$ c_e (current unstable)
   t2: c_d
@@ -280,7 +299,7 @@
   t0^ c_b (base)
   $ hg topic --list --color=debug
   [topic.stack.summary.topic|### topic: [topic.active|foo]]
-  [topic.stack.summary.branches|### branch: default]
+  [topic.stack.summary.branches|### target: default (branch)]
   [topic.stack.index topic.stack.index.unstable|t4][topic.stack.state topic.stack.state.unstable|$] [topic.stack.desc topic.stack.desc.unstable|c_f][topic.stack.state topic.stack.state.unstable| (unstable)]
   [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]
@@ -360,7 +379,7 @@
 
   $ hg top -l
   ### topic: foo (2 heads)
-  ### branch: default
+  ### target: default (branch)
   t6: c_f
   t5: c_e
   t2^ c_d (base)
@@ -404,7 +423,7 @@
 
   $ hg topic --list
   ### topic: foo (2 heads)
-  ### branch: default
+  ### target: default (branch)
   t6$ c_f (unstable)
   t5$ c_e (unstable)
   t2^ c_D (base)
@@ -422,3 +441,355 @@
   abort: cannot resolve "thisdoesnotexist": no such topic found
   [255]
 
+Complex cases where commits with same topic are not consecutive but are linear
+==============================================================================
+
+  $ hg log --graph
+  o  15 default {foo} draft c_h
+  |
+  o  14 default {foo} draft c_g
+  |
+  @  13 default {foo} draft c_D
+  |
+  | o  9 default {foo} draft c_f
+  | |
+  | o  8 default {foo} draft c_e
+  | |
+  | x  7 default {foo} draft c_d
+  |/
+  o  2 default {foo} draft c_c
+  |
+  o  1 default {} public c_b
+  |
+  o  0 default {} public c_a
+  
+Converting into a linear chain
+  $ hg rebase -s 'desc("c_e") - obsolete()' -d 'desc("c_h") - obsolete()'
+  rebasing 8:215bc359096a "c_e"
+  rebasing 9:ec9267b3f33f "c_f"
+
+  $ hg log -G
+  o  17 default {foo} draft c_f
+  |
+  o  16 default {foo} draft c_e
+  |
+  o  15 default {foo} draft c_h
+  |
+  o  14 default {foo} draft c_g
+  |
+  @  13 default {foo} draft c_D
+  |
+  o  2 default {foo} draft c_c
+  |
+  o  1 default {} public c_b
+  |
+  o  0 default {} public c_a
+  
+Changing topics on some commits in between
+  $ hg topic foobar -r 'desc(c_e) + desc(c_D)'
+  switching to topic foobar
+  changed topic on 2 changes
+  $ hg log -G
+  @  19 default {foobar} draft c_D
+  |
+  | o  18 default {foobar} draft c_e
+  | |
+  | | o  17 default {foo} draft c_f
+  | | |
+  | | x  16 default {foo} draft c_e
+  | |/
+  | o  15 default {foo} draft c_h
+  | |
+  | o  14 default {foo} draft c_g
+  | |
+  | x  13 default {foo} draft c_D
+  |/
+  o  2 default {foo} draft c_c
+  |
+  o  1 default {} public c_b
+  |
+  o  0 default {} public c_a
+  
+  $ hg rebase -s 'desc("c_f") - obsolete()' -d 'desc("c_e") - obsolete()'
+  rebasing 17:77082e55de88 "c_f"
+  switching to topic foo
+  switching to topic foobar
+  $ hg rebase -s 'desc("c_g") - obsolete()' -d 'desc("c_D") - obsolete()'
+  rebasing 14:0c3e8aed985d "c_g"
+  switching to topic foo
+  rebasing 15:b9e4f3709bc5 "c_h"
+  rebasing 18:4bc813530301 "c_e"
+  switching to topic foobar
+  rebasing 20:4406ea4be852 "c_f" (tip)
+  switching to topic foo
+  switching to topic foobar
+  $ hg up
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log --graph
+  o  24 default {foo} draft c_f
+  |
+  @  23 default {foobar} draft c_e
+  |
+  o  22 default {foo} draft c_h
+  |
+  o  21 default {foo} draft c_g
+  |
+  o  19 default {foobar} draft c_D
+  |
+  o  2 default {foo} draft c_c
+  |
+  o  1 default {} public c_b
+  |
+  o  0 default {} public c_a
+  
+XXX: The following should show single heads
+XXX: The behind count is weird, because the topic are interleaved.
+
+  $ hg stack
+  ### topic: foobar
+  ### target: default (branch), 3 behind
+  t2@ c_e (current)
+    ^ c_h
+  t1: c_D
+  t0^ c_c (base)
+
+  $ hg stack foo
+  ### topic: foo
+  ### target: default (branch), ambigious rebase destination - topic 'foo' has 3 heads
+  t4: c_f
+    ^ c_e
+  t3: c_h
+  t2: c_g
+    ^ c_D
+  t1: c_c
+  t0^ c_b (base)
+
+case involving a merge
+----------------------
+
+  $ cd ..
+  $ hg init stack-gap-merge
+  $ cd stack-gap-merge
+
+  $ echo aaa > aaa
+  $ hg commit -Am 'c_A'
+  adding aaa
+  $ hg topic red
+  marked working directory as topic: red
+  $ echo bbb > bbb
+  $ hg commit -Am 'c_B'
+  adding bbb
+  active topic 'red' grew its first changeset
+  $ echo ccc > ccc
+  $ hg commit -Am 'c_C'
+  adding ccc
+  $ hg topic blue
+  $ echo ddd > ddd
+  $ hg commit -Am 'c_D'
+  adding ddd
+  active topic 'blue' grew its first changeset
+  $ hg up 'desc("c_B")'
+  switching to topic red
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ echo eee > eee
+  $ hg commit -Am 'c_E'
+  adding eee
+  $ echo fff > fff
+  $ hg commit -Am 'c_F'
+  adding fff
+  $ hg topic blue
+  $ echo ggg > ggg
+  $ hg commit -Am 'c_G'
+  adding ggg
+  $ hg up 'desc("c_D")'
+  2 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ hg topic red
+  $ hg merge 'desc("c_G")'
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -Am 'c_H'
+  $ hg topic blue
+  $ echo iii > iii
+  $ hg ci -Am 'c_I'
+  adding iii
+
+  $ hg log -G
+  @  8 default {blue} draft c_I
+  |
+  o    7 default {red} draft c_H
+  |\
+  | o  6 default {blue} draft c_G
+  | |
+  | o  5 default {red} draft c_F
+  | |
+  | o  4 default {red} draft c_E
+  | |
+  o |  3 default {blue} draft c_D
+  | |
+  o |  2 default {red} draft c_C
+  |/
+  o  1 default {red} draft c_B
+  |
+  o  0 default {} draft c_A
+  
+
+  $ hg stack red
+  ### topic: red
+  ### target: default (branch), 6 behind
+  t5: c_H
+    ^ c_G
+    ^ c_D
+  t4: c_C
+  t1^ c_B (base)
+  t3: c_F
+  t2: c_E
+  t1: c_B
+  t0^ c_A (base)
+  $ hg stack blue
+  ### topic: blue
+  ### target: default (branch), ambigious rebase destination - topic 'blue' has 3 heads
+  t3@ c_I (current)
+    ^ c_H
+  t2: c_D
+    ^ c_C
+  t1: c_G
+  t0^ c_F (base)
+
+Even with some obsolete and orphan changesets
+
+(the ordering of each branch of "blue" change because their hash change. we
+should stabilize this eventuelly)
+
+  $ hg up 'desc("c_B")'
+  switching to topic red
+  0 files updated, 0 files merged, 6 files removed, 0 files unresolved
+  $ hg commit --amend --user test2
+  $ hg up 'desc("c_C")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg commit --amend --user test2
+  $ hg up 'desc("c_D")'
+  switching to topic blue
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg commit --amend --user test2
+
+  $ hg log -G --rev 'sort(all(), "topo")'
+  @  11 default {blue} draft c_D
+  |
+  | o  8 default {blue} draft c_I
+  | |
+  | o    7 default {red} draft c_H
+  | |\
+  | | o  6 default {blue} draft c_G
+  | | |
+  | | o  5 default {red} draft c_F
+  | | |
+  | | o  4 default {red} draft c_E
+  | | |
+  | x |  3 default {blue} draft c_D
+  |/ /
+  x /  2 default {red} draft c_C
+  |/
+  | o  10 default {red} draft c_C
+  |/
+  x  1 default {red} draft c_B
+  |
+  | o  9 default {red} draft c_B
+  |/
+  o  0 default {} draft c_A
+  
+
+  $ hg stack red
+  ### topic: red
+  ### target: default (branch), ambigious rebase destination - topic 'red' has 3 heads
+  t5$ c_H (unstable)
+    ^ c_G
+    ^ c_D
+  t4$ c_C (unstable)
+  t1^ c_B (base)
+  t3$ c_F (unstable)
+  t2$ c_E (unstable)
+  t1: c_B
+  t0^ c_A (base)
+  $ hg stack blue
+  ### topic: blue
+  ### target: default (branch), ambigious rebase destination - topic 'blue' has 3 heads
+  t3$ c_I (unstable)
+    ^ c_H
+  t2$ c_G (unstable)
+    ^ c_F
+  t1$ c_D (current unstable)
+  t0^ c_C (base)
+
+more obsolescence
+
+  $ hg up 'max(desc("c_H"))'
+  switching to topic red
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg commit --amend --user test3
+  $ hg up 'max(desc("c_G"))'
+  switching to topic blue
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ hg commit --amend --user test3
+  $ hg up 'max(desc("c_B"))'
+  switching to topic red
+  0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ hg commit --amend --user test3
+  $ hg up 'max(desc("c_C"))'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg commit --amend --user test3
+  $ hg up 'max(desc("c_D"))'
+  switching to topic blue
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg commit --amend --user test3
+
+  $ hg log -G --rev 'sort(all(), "topo")'
+  @  16 default {blue} draft c_D
+  |
+  | o  13 default {blue} draft c_G
+  | |
+  | | o    12 default {red} draft c_H
+  | | |\
+  | | | | o  8 default {blue} draft c_I
+  | | | | |
+  | | +---x  7 default {red} draft c_H
+  | | | |/
+  | +---x  6 default {blue} draft c_G
+  | | |
+  | o |  5 default {red} draft c_F
+  | | |
+  | o |  4 default {red} draft c_E
+  | | |
+  +---x  3 default {blue} draft c_D
+  | |
+  x |  2 default {red} draft c_C
+  |/
+  | o  15 default {red} draft c_C
+  |/
+  x  1 default {red} draft c_B
+  |
+  | o  14 default {red} draft c_B
+  |/
+  o  0 default {} draft c_A
+  
+
+  $ hg stack red
+  ### topic: red
+  ### target: default (branch), ambigious rebase destination - topic 'red' has 3 heads
+  t5$ c_H (unstable)
+    ^ c_G
+    ^ c_D
+  t4$ c_F (unstable)
+  t3$ c_E (unstable)
+  t1^ c_B (base)
+  t2$ c_C (unstable)
+  t1: c_B
+  t0^ c_A (base)
+  $ hg stack blue
+  ### topic: blue
+  ### target: default (branch), ambigious rebase destination - topic 'blue' has 3 heads
+  t3$ c_I (unstable)
+    ^ c_H
+  t2$ c_G (unstable)
+    ^ c_F
+  t1$ c_D (current unstable)
+  t0^ c_C (base)
--- a/tests/test-topic-tutorial.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic-tutorial.t	Wed Sep 27 01:12:47 2017 +0200
@@ -2,18 +2,27 @@
 Topic Tutorial
 ==============
 
-.. This test file is also supposed to be able to compile as a rest file.
+This Mercurial configuration example is used for testing.
 
-
-.. Some Setup::
+.. Various setup
 
   $ . "$TESTDIR/testlib/topic_setup.sh"
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > evolution=all
+  > [extensions]
+  > evolve=
+  > EOF
+
   $ hg init server
+
   $ cd server
+
   $ cat >> .hg/hgrc << EOF
   > [ui]
   > user= Shopping Master
   > EOF
+
   $ cat >> shopping << EOF
   > Spam
   > Whizzo butter
@@ -23,8 +32,10 @@
   > Blancmange
   > Salmon mousse
   > EOF
+
   $ hg commit -A -m "Shopping list"
   adding shopping
+
   $ cd ..
   $ hg clone server client
   updating to branch default
@@ -34,15 +45,71 @@
   > [ui]
   > user= Tutorial User
   > EOF
+#if docgraph-ext
+  $ . "$TESTDIR/testlib/docgraph_setup.sh" #rest-ignore
+#endif
 
 Topic branches are lightweight branches which disappear when changes are
-finalized (move to the public phase). They can help users to organise and share
+finalized (moved to the public phase). They can help users to organize and share
 their unfinished work.
 
+In this tutorial, we explain how to use topics for local development. In the first part,
+there is a central *publishing* server. Anything pushed to the central server will become public and immutable This means no unfinished work should escapes the local repository.
+
+
 Topic Basics
 ============
 
-Let's say we use Mercurial to manage our shopping list::
+Let's say we use Mercurial to manage our shopping list:
+
+  $ hg log --graph
+  @  changeset:   0:38da43f0a2ea
+     tag:         tip
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     Shopping list
+  
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      }
+#endif
+
+We are about to make some additions to this list and would like to do them
+within a topic. Creating a new topic is done using the ``topic`` command:
+
+  $ hg topics food
+  marked working directory as topic: food
+
+Much like a named branch, our topic is active but it does not contain any
+changeset yet:
+
+  $ hg topics
+   * food
+
+  $ hg summary
+  parent: 0:38da43f0a2ea tip
+   Shopping list
+  branch: default
+  commit: (clean)
+  update: (current)
+  topic:  food
 
   $ hg log --graph
   @  changeset:   0:38da43f0a2ea
@@ -52,32 +119,29 @@
      summary:     Shopping list
   
 
-We are about to make some additions to this list and would like to do them
-within a topic. Creating a new topic is done using the ``topic`` command::
-
-  $ hg topic food
-
-Much like a named branch, our topic is active but it does not contain any
-changesets yet::
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      }
+#endif
 
-  $ hg topic
-   * food
-  $ hg summary
-  parent: 0:38da43f0a2ea tip
-   Shopping list
-  branch: default
-  commit: (clean)
-  update: (current)
-  topic:  food
-  $ hg log --graph
-  @  changeset:   0:38da43f0a2ea
-     tag:         tip
-     user:        test
-     date:        Thu Jan 01 00:00:00 1970 +0000
-     summary:     Shopping list
-  
-
-Our next commit will be part of the active topic::
+Our next commit will be part of the active topic:
 
   $ cat >> shopping << EOF
   > Egg
@@ -85,7 +149,10 @@
   > Vinegar
   > Oil
   > EOF
+
   $ hg commit -m "adding condiments"
+  active topic 'food' grew its first changeset
+
   $ hg log --graph --rev 'topic("food")'
   @  changeset:   1:13900241408b
   |  tag:         tip
@@ -95,14 +162,38 @@
      summary:     adding condiments
   
 
-And future commits will be part of that topic too::
+#if docgraph-ext
+  $ hg docgraph -r "topic("food")" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      }
+#endif
+
+And future commits will be part of that topic too:
 
   $ cat >> shopping << EOF
   > Bananas
   > Pear
   > Apple
   > EOF
+
   $ hg commit -m "adding fruits"
+
   $ hg log --graph --rev 'topic("food")'
   @  changeset:   2:287de11b401f
   |  tag:         tip
@@ -118,25 +209,60 @@
      summary:     adding condiments
   
 
+#if docgraph-ext
+  $ hg docgraph -r "topic("food")" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	2	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=2,
+      		pin=true,
+      		pos="1,2!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 2	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
 We can get a compact view of the content of our topic using the ``stack``
-command::
+command:
 
   $ hg stack
   ### topic: food
-  ### branch: default
+  ### target: default (branch)
   t2@ adding fruits (current)
   t1: adding condiments
   t0^ Shopping list (base)
 
-The topic deactivates when we update away from it::
+The topic deactivates when we update away from it:
 
-  $ hg up default
+  $ hg update default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg topic
+
+  $ hg topics
      food
 
 Note that ``default`` (name of the branch) now refers to the tipmost
-changeset of default without a topic::
+changeset of default without a topic:
 
   $ hg log --graph
   o  changeset:   2:287de11b401f
@@ -158,26 +284,74 @@
      summary:     Shopping list
   
 
-And updating back to the topic reactivates it::
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	2	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=2,
+      		pin=true,
+      		pos="1,2!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 2	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+And updating back to the topic reactivates it:
 
-  $ hg up food
+  $ hg update food
   switching to topic food
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg topic
+
+  $ hg topics
    * food
 
 Updating to any changeset that is part of a topic activates the topic
-regardless of how the revision was specified::
+regardless of how the revision was specified:
 
-  $ hg up default
+  $ hg update default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg up --rev 'desc("condiments")'
+
+  $ hg update --rev 'desc("condiments")'
   switching to topic food
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg topic
+
+  $ hg topics
    * food
 
-.. server side activity::
+.. Server side activity:
 
   $ cd ../server/
   $ cat > shopping << EOF
@@ -191,11 +365,13 @@
   > Blancmange
   > Salmon mousse
   > EOF
+
   $ hg commit -A -m "Adding clothes"
+
   $ cd ../client
 
 The topic will also affect the rebase and the merge destinations. Let's pull
-the latest update from the main server::
+the latest update from the main server:
 
   $ hg pull
   pulling from $TESTTMP/server (glob)
@@ -205,6 +381,7 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   (run 'hg heads' to see heads)
+
   $ hg log -G
   o  changeset:   3:6104862e8b84
   |  tag:         tip
@@ -230,28 +407,88 @@
      date:        Thu Jan 01 00:00:00 1970 +0000
      summary:     Shopping list
   
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	3	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=3,
+      		pin=true,
+      		pos="1,3!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 3	 [arrowhead=none,
+      		penwidth=2.0];
+      	2	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=2,
+      		pin=true,
+      		pos="1,2!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 2	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 The topic head will not be considered when merging from the new head of the
-branch::
+branch:
 
-  $ hg up default
+  $ hg update default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
   $ hg merge
   abort: branch 'default' has one head - please merge with an explicit rev
   (run 'hg heads' to see all heads)
   [255]
 
-But the topic will see that branch head as a valid destination::
+But the topic will see that branch head as a valid destination:
 
-  $ hg up food
+  $ hg update food
   switching to topic food
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
   $ hg rebase
   rebasing 1:13900241408b "adding condiments"
   merging shopping
   switching to topic food
   rebasing 2:287de11b401f "adding fruits"
   merging shopping
+
   $ hg log --graph
   @  changeset:   5:2d50db8b5b4c
   |  tag:         tip
@@ -277,11 +514,69 @@
      date:        Thu Jan 01 00:00:00 1970 +0000
      summary:     Shopping list
   
-
-The topic information will disappear when we publish the changesets::
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=3,
+      		pin=true,
+      		pos="1,3!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 3	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	3 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	4 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
-  $ hg topic
+The topic information will disappear when we publish the changesets:
+
+  $ hg topics
    * food
+
   $ hg push
   pushing to $TESTTMP/server (glob)
   searching for changes
@@ -290,8 +585,20 @@
   adding file changes
   added 2 changesets with 2 changes to 1 files
   2 new obsolescence markers
-  $ hg topic
+  active topic 'food' is now empty
+
+  $ hg topics
    * food
+
+The topic still exists, and any new commit will be in the topic. But
+note that it is now devoid of any commit.
+
+  $ hg topics --list
+  ### topic: food
+  ### target: default (branch)
+  (stack is empty)
+  t0^ adding fruits (base)
+
   $ hg log --graph
   @  changeset:   5:2d50db8b5b4c
   |  tag:         tip
@@ -315,88 +622,197 @@
      date:        Thu Jan 01 00:00:00 1970 +0000
      summary:     Shopping list
   
-  $ hg up default
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=3,
+      		pin=true,
+      		pos="1,3!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 3	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	4 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+If we update to the *default* head, we will leave the topic behind,
+and since it is commit-less, it will vanish.
+
+  $ hg update default
+  clearing empty topic "food"
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
+From there, the topic has been completely forgotten.
+
+  $ hg topics
+
+
+Keep working within topics
+==========================
+
+Making sure all your new local commit are made within a topic will help your
+organise your work. It is possible to ensure this through the Mercurial
+configuration.
+
+For this tutorial, we'll add the config at the repository level:
+
+  $ cat << EOF >> .hg/hgrc
+  > [experimental]
+  > enforce-topic = yes
+  > EOF
+
+You can also use `hg config --edit` to update your mercurial configuration.
+
+
+Once enforcement is turned on. New local commit will be denied if no topic is active.
+
+  $ echo sickle >> shopping
+  $ hg commit -m 'Adding sickle'
+  abort: no active topic
+  (set a current topic or use '--config experimental.enforce-topic=no' to commit without a topic)
+  [255]
+
+Ok, let's clean this up and delve into multiple topics.
+
+  $ hg revert .
+  reverting shopping
+
+
 Working with Multiple Topics
 ============================
 
-In the above example, topics do not bring much benefit since you only have one
+In the above example, topics do not bring much benefits since you only have one
 line of development. Topics start to be more useful when you have to work on
 multiple features at the same time.
 
 We might go shopping in a hardware store in the same go, so let's add some
-tools to the shopping list within a new topic::
+tools to the shopping list within a new topic:
 
-  $ hg topic tools
+  $ hg topics tools
+  marked working directory as topic: tools
   $ echo hammer >> shopping
-  $ hg ci -m 'Adding hammer'
+  $ hg commit -m 'Adding hammer'
+  active topic 'tools' grew its first changeset
+
   $ echo saw >> shopping
-  $ hg ci -m 'Adding saw'
+  $ hg commit -m 'Adding saw'
+
   $ echo drill >> shopping
-  $ hg ci -m 'Adding drill'
+  $ hg commit -m 'Adding drill'
 
 But we are not sure we will actually go to the hardware store, so in the
 meantime, we want to extend the list with drinks. We go back to the official
-default branch and start a new topic::
+default branch and start a new topic:
 
-  $ hg up default
+  $ hg update default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg topic drinks
+
+  $ hg topics drinks
+  marked working directory as topic: drinks
   $ echo 'apple juice' >> shopping
-  $ hg ci -m 'Adding apple juice'
-  $ echo 'orange juice' >> shopping
-  $ hg ci -m 'Adding orange juice'
+  $ hg commit -m 'Adding apple juice'
+  active topic 'drinks' grew its first changeset
 
-We now have two topics::
+  $ echo 'orange juice' >> shopping
+  $ hg commit -m 'Adding orange juice'
 
-  $ hg topic
+We now have two topics:
+
+  $ hg topics
    * drinks
      tools
 
-The information displayed by ``hg stack`` adapts to the active topic::
+The information displayed by ``hg stack`` adapts to the active topic:
 
   $ hg stack
   ### topic: drinks
-  ### branch: default
+  ### target: default (branch)
   t2@ Adding orange juice (current)
   t1: Adding apple juice
   t0^ adding fruits (base)
-  $ hg up tools
+
+  $ hg update tools
   switching to topic tools
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
   $ hg stack
   ### topic: tools
-  ### branch: default
+  ### target: default (branch)
   t3@ Adding drill (current)
   t2: Adding saw
   t1: Adding hammer
   t0^ adding fruits (base)
 
 They are seen as independent branches by Mercurial. No rebase or merge
-between them will be attempted by default::
+between them will be attempted by default:
 
   $ hg rebase
   nothing to rebase
   [1]
 
-.. server activity::
+We simulate independant contributions to the repo with this
+activity:
 
   $ cd ../server
-  $ hg up
+  $ hg update
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ mv shopping foo
   $ echo 'Coat' > shopping
   $ cat foo >> shopping
-  $ hg ci -m 'add a coat'
+  $ hg commit -m 'add a coat'
   $ echo 'Coat' > shopping
   $ echo 'Shoes' >> shopping
   $ cat foo >> shopping
   $ rm foo
-  $ hg ci -m 'add a pair of shoes'
+  $ hg commit -m 'add a pair of shoes'
   $ cd ../client
 
-Let's see what other people did in the meantime::
+Let's discover what other people did contribute:
 
   $ hg pull
   pulling from $TESTTMP/server (glob)
@@ -408,7 +824,214 @@
   (run 'hg heads' to see heads)
 
 There are new changes! We can simply use ``hg rebase`` to update our
-changeset on top of the latest::
+changeset on top of the latest:
+
+  $ hg log -G
+  o  changeset:   12:fbff9bc37a43
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a pair of shoes
+  |
+  o  changeset:   11:f2d6cacc6115
+  |  parent:      5:2d50db8b5b4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a coat
+  |
+  | o  changeset:   10:70dfa201ed73
+  | |  topic:       drinks
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding orange juice
+  | |
+  | o  changeset:   9:8dfa45bd5e0c
+  |/   topic:       drinks
+  |    parent:      5:2d50db8b5b4c
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding apple juice
+  |
+  | @  changeset:   8:34255b455dac
+  | |  topic:       tools
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding drill
+  | |
+  | o  changeset:   7:cffff85af537
+  | |  topic:       tools
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding saw
+  | |
+  | o  changeset:   6:183984ef46d1
+  |/   topic:       tools
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding hammer
+  |
+  o  changeset:   5:2d50db8b5b4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     adding fruits
+  |
+  o  changeset:   4:4011b46eeb33
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     adding condiments
+  |
+  o  changeset:   3:6104862e8b84
+  |  parent:      0:38da43f0a2ea
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding clothes
+  |
+  o  changeset:   0:38da43f0a2ea
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     Shopping list
+  
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=3,
+      		pin=true,
+      		pos="1,3!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 3	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	4 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	9	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=9,
+      		pin=true,
+      		pos="1,9!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	5 -> 9	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	8	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=8,
+      		pin=true,
+      		pos="1,8!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	7 -> 8	 [arrowhead=none,
+      		penwidth=2.0];
+      	10	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=10,
+      		pin=true,
+      		pos="1,10!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	9 -> 10	 [arrowhead=none,
+      		penwidth=2.0];
+      	12	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="1,12!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	11 -> 12	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
   $ hg rebase
   rebasing 6:183984ef46d1 "Adding hammer"
@@ -419,17 +1042,16 @@
   rebasing 8:34255b455dac "Adding drill"
   merging shopping
 
-But what about the other topic? You can use 'hg topic --verbose' to see
-information about all the topics::
+But what about the other topic? You can use 'hg topics --verbose' to see
+information about all the topics:
 
-  $ hg topic --verbose
+  $ hg topics --verbose
      drinks (on branch: default, 2 changesets, 2 behind)
    * tools  (on branch: default, 3 changesets)
 
-The "2 behind" is telling you that there are 2 new changesets on the named
-branch of the topic. You need to merge or rebase to incorporate them.
+The "2 behind" is telling you that there are 2 new changesets over the base of the topic.
 
-Pushing that topic would create a new head, and therefore will be prevented::
+Pushing that topic would create a new head, and therefore will be prevented:
 
   $ hg push --rev drinks
   pushing to $TESTTMP/server (glob)
@@ -439,8 +1061,9 @@
   [255]
 
 
-Even after a rebase, pushing all active topics at the same time will complain
-about the multiple heads it would create on that branch::
+Even after a rebase, pushing all active topics at the same time would publish
+them to the default branch, and then mercurial would complain about the
+multiple *public* heads it would create on that branch:
 
   $ hg rebase -b drinks
   rebasing 9:8dfa45bd5e0c "Adding apple juice"
@@ -449,6 +1072,7 @@
   rebasing 10:70dfa201ed73 "Adding orange juice"
   merging shopping
   switching to topic tools
+
   $ hg push
   pushing to $TESTTMP/server (glob)
   searching for changes
@@ -457,7 +1081,7 @@
   [255]
 
 Publishing only one of them is allowed (as long as it does not create a new
-branch head as we just saw in the previous case)::
+branch head as we just saw in the previous case):
 
   $ hg push -r drinks
   pushing to $TESTTMP/server (glob)
@@ -469,15 +1093,792 @@
   2 new obsolescence markers
 
 The published topic has now disappeared, and the other is now marked as
-"behind"::
+"behind":
+
+  $ hg topics --verbose
+   * tools (on branch: default, 3 changesets, 2 behind)
 
-  $ hg topic --verbose
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3@ Adding drill (current)
+  t2: Adding saw
+  t1: Adding hammer
+  t0^ add a pair of shoes (base)
+
+Working Within Your Stack
+===========================
+
+Navigating within your stack
+----------------------------
+
+As we saw before `stack` displays changesets on your current topic in a clean way:
+
+  $ hg topics --verbose
    * tools (on branch: default, 3 changesets, 2 behind)
+
   $ hg stack
   ### topic: tools
-  ### branch: default, 2 behind
+  ### target: default (branch), 2 behind
+  t3@ Adding drill (current)
+  t2: Adding saw
+  t1: Adding hammer
+  t0^ add a pair of shoes (base)
+
+You can navigate in your current stack with `previous` and `next`.
+
+`previous` will bring you back to the parent of the topic head.
+
+  $ hg previous
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  [14] Adding saw
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3: Adding drill
+  t2@ Adding saw (current)
+  t1: Adding hammer
+  t0^ add a pair of shoes (base)
+
+`next` will move you forward to the topic head.
+
+  $ hg next
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  [15] Adding drill
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
   t3@ Adding drill (current)
   t2: Adding saw
   t1: Adding hammer
   t0^ add a pair of shoes (base)
 
+You can also directly jump to a changeset within your stack with the revset `t#`.
+
+  $ hg update t1
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3: Adding drill
+  t2: Adding saw
+  t1@ Adding hammer (current)
+  t0^ add a pair of shoes (base)
+
+Editing your work mid-stack
+---------------------------
+
+It's easy to edit your work inside your stack:
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3: Adding drill
+  t2: Adding saw
+  t1@ Adding hammer (current)
+  t0^ add a pair of shoes (base)
+
+  $ hg amend -m "Adding hammer to the shopping list"
+  2 new unstable changesets
+
+Understanding the current situation with hg log is not so easy, because
+it shows too many things:
+
+  $ hg log -G -r "t0::"
+  @  changeset:   18:b7509bd417f8
+  |  tag:         tip
+  |  topic:       tools
+  |  parent:      12:fbff9bc37a43
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding hammer to the shopping list
+  |
+  | o  changeset:   17:4cd7c1591a67
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding orange juice
+  | |
+  | o  changeset:   16:20759cb47ff8
+  |/   parent:      12:fbff9bc37a43
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding apple juice
+  |
+  | o  changeset:   15:bb1e6254f532
+  | |  topic:       tools
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  trouble:     unstable
+  | |  summary:     Adding drill
+  | |
+  | o  changeset:   14:d4f97f32f8a1
+  | |  topic:       tools
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  trouble:     unstable
+  | |  summary:     Adding saw
+  | |
+  | x  changeset:   13:a8ab3599d53d
+  |/   topic:       tools
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding hammer
+  |
+  o  changeset:   12:fbff9bc37a43
+  |  user:        test
+  ~  date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add a pair of shoes
+  
+
+#if docgraph-ext
+  $ hg docgraph -r "t0::" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	12	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="1,12!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	13	 [fillcolor="#DFDFFF",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=13,
+      		pin=true,
+      		pos="2,13!",
+      		shape=pentagon,
+      		style="dotted, filled",
+      		width=0.5];
+      	12 -> 13	 [arrowhead=none,
+      		penwidth=2.0];
+      	18	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=18,
+      		pin=true,
+      		pos="1,18!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	12 -> 18	 [arrowhead=none,
+      		penwidth=2.0];
+      	16	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="1,16!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	12 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      	13 -> 18	 [arrowhead=none,
+      		minlen=0,
+      		penwidth=2.0,
+      		style=dashed];
+      	14	 [fillcolor="#FF4F4F",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="2,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	13 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	15	 [fillcolor="#FF4F4F",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=15,
+      		pin=true,
+      		pos="2,15!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	14 -> 15	 [arrowhead=none,
+      		penwidth=2.0];
+      	17	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="1,17!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	16 -> 17	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+Fortunately stack shows you a better visualization:
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3$ Adding drill (unstable)
+  t2$ Adding saw (unstable)
+  t1@ Adding hammer to the shopping list (current)
+  t0^ add a pair of shoes (base)
+
+It's easy to stabilize the situation, `next` has an `--evolve` option.  It will
+do the necessary relocation of `t2` and `t3` over the new `t1` without having
+to do that rebase by hand.:
+
+  $ hg next --evolve
+  move:[14] Adding saw
+  atop:[18] Adding hammer to the shopping list
+  working directory now at d5c51ee5762a
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3$ Adding drill (unstable)
+  t2@ Adding saw (current)
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
+
+One more to go:
+
+  $ hg next --evolve
+  move:[15] Adding drill
+  atop:[19] Adding saw
+  working directory now at bae3758e46bf
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t3@ Adding drill (current)
+  t2: Adding saw
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
+
+Let's take a look at `hg log` once again:
+
+  $ hg log -G -r "t0::"
+  @  changeset:   20:bae3758e46bf
+  |  tag:         tip
+  |  topic:       tools
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding drill
+  |
+  o  changeset:   19:d5c51ee5762a
+  |  topic:       tools
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding saw
+  |
+  o  changeset:   18:b7509bd417f8
+  |  topic:       tools
+  |  parent:      12:fbff9bc37a43
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding hammer to the shopping list
+  |
+  | o  changeset:   17:4cd7c1591a67
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding orange juice
+  | |
+  | o  changeset:   16:20759cb47ff8
+  |/   parent:      12:fbff9bc37a43
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding apple juice
+  |
+  o  changeset:   12:fbff9bc37a43
+  |  user:        test
+  ~  date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add a pair of shoes
+  
+
+#if docgraph-ext
+  $ hg docgraph -r "t0::" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	12	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="1,12!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	16	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="1,16!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	12 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      	18	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=18,
+      		pin=true,
+      		pos="1,18!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	12 -> 18	 [arrowhead=none,
+      		penwidth=2.0];
+      	17	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="1,17!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	16 -> 17	 [arrowhead=none,
+      		penwidth=2.0];
+      	19	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=19,
+      		pin=true,
+      		pos="1,19!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	18 -> 19	 [arrowhead=none,
+      		penwidth=2.0];
+      	20	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=20,
+      		pin=true,
+      		pos="1,20!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	19 -> 20	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+Multi-headed stack
+------------------
+
+Stack is also very helpful when you have a multi-headed stack:
+
+  $ hg up t1
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ echo "nails" > new_shopping
+  $ cat shopping >> new_shopping
+  $ mv new_shopping shopping
+
+  $ hg commit -m 'Adding nails'
+
+  $ hg stack
+  ### topic: tools (2 heads)
+  ### target: default (branch), 2 behind
+  t4: Adding drill
+  t3: Adding saw
+  t1^ Adding hammer to the shopping list (base)
+  t2@ Adding nails (current)
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
+
+Solving this situation is easy with a topic: use merge or rebase.
+Merge within a multi-headed stack will use the other topic head as
+destination if the topic has two heads. But rebasing will yield a
+completely linear history so it's what we will do.
+
+  $ hg log -G
+  @  changeset:   21:f936c6da9d61
+  |  tag:         tip
+  |  topic:       tools
+  |  parent:      18:b7509bd417f8
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding nails
+  |
+  | o  changeset:   20:bae3758e46bf
+  | |  topic:       tools
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding drill
+  | |
+  | o  changeset:   19:d5c51ee5762a
+  |/   topic:       tools
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding saw
+  |
+  o  changeset:   18:b7509bd417f8
+  |  topic:       tools
+  |  parent:      12:fbff9bc37a43
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding hammer to the shopping list
+  |
+  | o  changeset:   17:4cd7c1591a67
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     Adding orange juice
+  | |
+  | o  changeset:   16:20759cb47ff8
+  |/   parent:      12:fbff9bc37a43
+  |    user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     Adding apple juice
+  |
+  o  changeset:   12:fbff9bc37a43
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a pair of shoes
+  |
+  o  changeset:   11:f2d6cacc6115
+  |  parent:      5:2d50db8b5b4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a coat
+  |
+  o  changeset:   5:2d50db8b5b4c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     adding fruits
+  |
+  o  changeset:   4:4011b46eeb33
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     adding condiments
+  |
+  o  changeset:   3:6104862e8b84
+  |  parent:      0:38da43f0a2ea
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     Adding clothes
+  |
+  o  changeset:   0:38da43f0a2ea
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     Shopping list
+  
+
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=3,
+      		pin=true,
+      		pos="1,3!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 3	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	3 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	4 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	12	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="1,12!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	11 -> 12	 [arrowhead=none,
+      		penwidth=2.0];
+      	16	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="1,16!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	12 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      	18	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=18,
+      		pin=true,
+      		pos="1,18!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	12 -> 18	 [arrowhead=none,
+      		penwidth=2.0];
+      	17	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="1,17!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	16 -> 17	 [arrowhead=none,
+      		penwidth=2.0];
+      	19	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=19,
+      		pin=true,
+      		pos="1,19!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	18 -> 19	 [arrowhead=none,
+      		penwidth=2.0];
+      	21	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=21,
+      		pin=true,
+      		pos="1,21!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	18 -> 21	 [arrowhead=none,
+      		penwidth=2.0];
+      	20	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=20,
+      		pin=true,
+      		pos="1,20!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	19 -> 20	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+  $ hg up t4
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg rebase
+  rebasing 19:d5c51ee5762a "Adding saw"
+  merging shopping
+  rebasing 20:bae3758e46bf "Adding drill"
+  merging shopping
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t4@ Adding drill (current)
+  t3: Adding saw
+  t2: Adding nails
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
+
+Collaborating through a non-publishing server
+=============================================
+
+.. setup:
+
+.. Let's create a non-publishing server:
+
+  $ cd ..
+
+  $ hg clone server non-publishing-server
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ cd non-publishing-server
+  $ cat >> .hg/hgrc << EOF
+  > [phases]
+  > publish = false
+  > EOF
+
+.. And another client:
+
+  $ cd ..
+
+  $ hg clone server other-client
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ cd client
+
+We can now share these draft changesets:
+(4.1-tests needs the --force to proceed with the test)
+
+  $ hg push ../non-publishing-server -r tools --force
+  pushing to ../non-publishing-server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 1 files (+1 heads)
+  8 new obsolescence markers
+
+Pushing the new topic branch to a non publishing server did not require
+--force. As long as new heads are on their own topic, Mercurial will not
+complain about them.
+
+From another client, we will get them with their topic:
+
+  $ cd ../other-client
+
+  $ hg pull ../non-publishing-server
+  pulling from ../non-publishing-server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 1 files (+1 heads)
+  8 new obsolescence markers
+  (run 'hg heads' to see heads)
+
+  $ hg topics --verbose
+     tools (on branch: default, 4 changesets, 2 behind)
+
+  $ hg up tools
+  switching to topic tools
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t4@ Adding drill (current)
+  t3: Adding saw
+  t2: Adding nails
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
+
+We can also add new changesets and share them:
+(4.1-tests needs the --force to proceed with the test)
+
+  $ echo screws >> shopping
+
+  $ hg commit -A -m "Adding screws"
+
+  $ hg push ../non-publishing-server --force
+  pushing to ../non-publishing-server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+
+And retrieve them on the first client:
+
+  $ cd ../client
+
+  $ hg pull ../non-publishing-server
+  pulling from ../non-publishing-server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  (run 'hg update' to get a working copy)
+
+  $ hg update
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg stack
+  ### topic: tools
+  ### target: default (branch), 2 behind
+  t5@ Adding screws (current)
+  t4: Adding drill
+  t3: Adding saw
+  t2: Adding nails
+  t1: Adding hammer to the shopping list
+  t0^ add a pair of shoes (base)
--- a/tests/test-topic.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-topic.t	Wed Sep 27 01:12:47 2017 +0200
@@ -1,6 +1,6 @@
   $ . "$TESTDIR/testlib/topic_setup.sh"
 
-  $ hg init pinky
+  $ hg init pinky --traceback
   $ cd pinky
   $ cat <<EOF >> .hg/hgrc
   > [phases]
@@ -19,34 +19,46 @@
   see all topics.
   
       Clear topic on existing topiced revisions:
-          'hg topic --rev <related revset> --clear'
+  
+        hg topics --rev <related revset> --clear
   
       Change topic on some revisions:
-          'hg topic <newtopicname> --rev <related revset>'
+  
+        hg topics <newtopicname> --rev <related revset>
   
       Clear current topic:
-          'hg topic --clear'
+  
+        hg topics --clear
   
       Set current topic:
-          'hg topic <topicname>'
+  
+        hg topics <topicname>
   
       List of topics:
-          'hg topics'
+  
+        hg topics
   
-      List of topics with their last touched time sorted according to it:
-          'hg topic --age'
+      List of topics sorted according to their last touched time displaying last
+      touched time and the user who last touched the topic:
+  
+        hg topics --age
   
       The active topic (if any) will be prepended with a "*".
   
+      The '--current' flag helps to take active topic into account. For example,
+      if you want to set the topic on all the draft changesets to the active
+      topic, you can do: 'hg topics -r "draft()" --current'
+  
       The --verbose version of this command display various information on the
       state of each topic.
   
-  options:
+  options ([+] can be repeated):
   
-      --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
+      --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
+      --current     display the current topic only
   
   (some details hidden, use --verbose to show complete help)
   $ hg topics
@@ -72,6 +84,36 @@
 
 Still no topics
   $ hg topics
+  $ hg topics --current
+  no active topic
+  [1]
+  $ hg topics --current somerandomtopic
+  abort: cannot use --current when setting a topic
+  [255]
+  $ hg topics --current --clear
+  abort: cannot use --current and --clear
+  [255]
+  $ hg topics --clear somerandomtopic
+  abort: cannot use --clear when setting a topic
+  [255]
+
+Trying some invalid topicnames
+
+  $ hg topic '.'
+  abort: the name '.' is reserved
+  [255]
+  $ hg topic null
+  abort: the name 'null' is reserved
+  [255]
+  $ hg topic tip
+  abort: the name 'tip' is reserved
+  [255]
+  $ hg topic 12345
+  abort: cannot use an integer as a name
+  [255]
+  $ hg topic '   '
+  abort: topic name cannot consist entirely of whitespaces
+  [255]
 
 Test commit flag and help text
 
@@ -93,19 +135,35 @@
    * topicflag
 
 Make a topic
+
   $ hg topic narf
   $ hg topics
    * narf
+  $ hg topics -v
+   * narf (on branch: default, 0 changesets)
+  $ hg stack
+  ### topic: narf
+  ### target: default (branch)
+  (stack is empty)
+  t0^ Add file delta (base)
+
+Add commits to topic
+
   $ echo topic work >> alpha
   $ hg ci -m 'start on narf'
+  active topic 'narf' grew its first changeset
   $ hg co .^
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg topic fran
+  marked working directory as topic: fran
   $ hg topics
    * fran
      narf
+  $ hg topics --current
+  fran
   $ echo >> fran work >> beta
   $ hg ci -m 'start on fran'
+  active topic 'fran' grew its first changeset
   $ hg co narf
   switching to topic narf
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -260,7 +318,9 @@
   $ hg topic
   $ echo what >> alpha
   $ hg topic query
+  marked working directory as topic: query
   $ hg ci -m 'what is narf, pinky?'
+  active topic 'query' grew its first changeset
   $ hg log -Gl2
   @  changeset:   5:c01515cfc331
   |  tag:         tip
@@ -274,6 +334,7 @@
   |  date:        Thu Jan 01 00:00:00 1970 +0000
   |  summary:     start on narf
   |
+
   $ hg push -f ../pinky -r query
   pushing to ../pinky
   searching for changes
@@ -281,6 +342,7 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
+
   $ hg -R ../pinky log -Gl 4
   o  changeset:   7:c01515cfc331
   |  tag:         tip
@@ -309,6 +371,7 @@
   |    date:        Thu Jan 01 00:00:00 1970 +0000
   |    summary:     start on narf
   |
+
   $ hg topics
    * query
   $ cd ../pinky
@@ -342,6 +405,7 @@
   query
   tip
   $ hg phase --public narf
+  active topic 'narf' is now empty
 
 POSSIBLE BUG: narf topic stays alive even though we just made all
 narf commits public:
@@ -387,6 +451,7 @@
   |    date:        Thu Jan 01 00:00:00 1970 +0000
   |    summary:     start on narf
   |
+
   $ cd ../brain
   $ hg topics
    * query
@@ -401,6 +466,7 @@
   adding manifests
   adding file changes
   added 3 changesets with 3 changes to 1 files
+  active topic 'query' is now empty
   (run 'hg update' to get a working copy)
   $ hg topics
    * query
@@ -432,6 +498,7 @@
 disappear:
 
   $ hg topics --clear
+  clearing empty topic "query"
   $ hg topics
      fran
 
@@ -670,7 +737,9 @@
 Amend a topic
 
   $ hg topic watwat
+  marked working directory as topic: watwat
   $ hg ci --amend
+  active topic 'watwat' grew its first changeset
   $ hg log -Gr 'draft()'
   @  changeset:   16:6c40a4c21bbe
   |  tag:         tip
@@ -725,9 +794,13 @@
   |  summary:     start on fran
   |
 
-  $ hg topics --rev '13::19' changewat
-  switching to topic changewat
+Using the current flag
+
+  $ hg topic changewat
+  $ hg topics --rev '13::19' --current
+  active topic 'changewat' grew its 2 first changesets
   changed topic on 2 changes
+
   $ hg log -Gr 'draft()'
   @  changeset:   21:56c83be6105f
   |  tag:         tip
@@ -752,6 +825,7 @@
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ echo gamma >> gamma
   $ hg ci -m gamma
+
   $ hg log -Gr 'draft()'
   @  changeset:   22:0d3d805542b4
   |  tag:         tip
@@ -774,9 +848,12 @@
   |  date:        Thu Jan 01 00:00:00 1970 +0000
   |  summary:     start on fran
   |
+
   $ hg topics --rev 't1::' changewut
   switching to topic changewut
+  active topic 'changewat' is now empty
   changed topic on 3 changes
+
   $ hg log -Gr 'draft()'
   @  changeset:   25:729ed5717393
   |  tag:         tip
@@ -805,20 +882,22 @@
 
   $ hg stack
   ### topic: changewut (2 heads)
-  ### branch: default, 5 behind
+  ### target: default (branch), 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
+  ### target: default (branch), 5 behind
   t3: fran?
   t1^ start on fran (base)
   t2: gamma
@@ -826,7 +905,7 @@
   t0^ Add file delta (base)
 
   $ hg topics --age
-   * changewut (*) (glob)
+   * changewut (* by test) (glob)
 
   $ cd ..
 
@@ -864,50 +943,63 @@
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     added a
   
+Testing the --age flag for `hg topics`
+======================================
+
   $ hg topic topic1970 --rev 0
   switching to topic topic1970
   changed topic on 1 changes
+
   $ hg add b
   $ hg topic topic1990
-  $ hg ci -m "Added b" --config devel.default-date="631152000 0" --date "631152000 0"
+  $ hg ci -m "Added b" --config devel.default-date="631152000 0" --user "foo" --date "631152000 0"
+  active topic 'topic1990' grew its first changeset
   $ hg add c
   $ hg topic topic2010
-  $ hg ci -m "Added c" --config devel.default-date="1262304000 0" --date "1262304000 0"
-  $ hg log
-  changeset:   3:9048b194797d
-  tag:         tip
-  topic:       topic2010
-  user:        test
-  date:        Fri Jan 01 00:00:00 2010 +0000
-  summary:     Added c
-  
-  changeset:   2:186d493c7f8d
-  topic:       topic1990
-  user:        test
-  date:        Mon Jan 01 00:00:00 1990 +0000
-  summary:     Added b
-  
-  changeset:   1:e5a30a141954
-  topic:       topic1970
-  parent:      -1:000000000000
-  user:        test
-  date:        Thu Jan 01 00:00:00 1970 +0000
-  summary:     added a
+  $ hg ci -m "Added c" --config devel.default-date="1262304000 0" --user "bar" --date "1262304000 0"
+  active topic 'topic2010' grew its first changeset
+
+  $ hg log -G
+  @  changeset:   3:76b16af75125
+  |  tag:         tip
+  |  topic:       topic2010
+  |  user:        bar
+  |  date:        Fri Jan 01 00:00:00 2010 +0000
+  |  summary:     Added c
+  |
+  o  changeset:   2:bba5bde53608
+  |  topic:       topic1990
+  |  user:        foo
+  |  date:        Mon Jan 01 00:00:00 1990 +0000
+  |  summary:     Added b
+  |
+  o  changeset:   1:e5a30a141954
+     topic:       topic1970
+     parent:      -1:000000000000
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     added a
   
   $ hg topics
      topic1970
      topic1990
    * topic2010
+
   $ hg topics --age
-     topic1970 (*) (glob)
-   * topic2010 (2010-01-01)
-     topic1990 (1990-01-01)
+     topic1970 (* second ago by test) (glob)
+   * topic2010 (* by bar) (glob)
+     topic1990 (* by foo) (glob)
+
   $ hg up topic1970
   switching to topic topic1970
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
   $ hg topics --age
-   * topic1970 (*) (glob)
-     topic2010 (2010-01-01)
-     topic1990 (1990-01-01)
+   * topic1970 (* by test) (glob)
+     topic2010 (* by bar) (glob)
+     topic1990 (* by foo) (glob)
 
+  $ hg topics --age random
+  abort: cannot use --age while setting a topic
+  [255]
   $ cd ..
--- a/tests/test-touch.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-touch.t	Wed Sep 27 01:12:47 2017 +0200
@@ -18,7 +18,7 @@
 Basic usage
 
   $ hg log -G
-  @  0:e93df3427f45 a
+  @  0:[0-9a-f]{12} a (re)
   
   $ hg touch .
   $ hg log -G
@@ -50,16 +50,18 @@
   
   o  3:[0-9a-f]{12} ab (re)
   
-  $ hg prune 3
+  $ hg prune 4
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  working directory now at 000000000000
   1 changesets pruned
 
 Duplicate
 
   $ hg touch --duplicate .
   $ hg log -G
-  @  5:[0-9a-f]{12} a (re)
+  @  5:[0-9a-f]{12} (re)
   
-  o  4:[0-9a-f]{12} a (re)
+  o  3:[0-9a-f]{12} ab (re)
   
 
 Multiple touch
@@ -75,19 +77,19 @@
   |
   o  6:[0-9a-f]{12} c (re)
   |
-  o  5:[0-9a-f]{12} a (re)
+  o  5:[0-9a-f]{12} (re)
   
-  o  4:[0-9a-f]{12} a (re)
+  o  3:[0-9a-f]{12} ab (re)
   
-  $ hg touch 6:7
+  $ hg touch .^:.
   $ hg log -G
   @  9:[0-9a-f]{12} d (re)
   |
   o  8:[0-9a-f]{12} c (re)
   |
-  o  5:[0-9a-f]{12} a (re)
+  o  5:[0-9a-f]{12} (re)
   
-  o  4:[0-9a-f]{12} a (re)
+  o  3:[0-9a-f]{12} ab (re)
   
 
 check move data kept after rebase on touch:
@@ -107,8 +109,36 @@
   $ hg touch
   1 new unstable changesets
 
+  $ hg log -G --hidden
+  | o  10:[0-9a-f]{12} move (re)
+  |
+  | x  9:[0-9a-f]{12} gna1 (re)
+  | |
+  | x  6:[0-9a-f]{12} d (re)
+  |/
+  | x  5:[0-9a-f]{12} c (re)
+  |
+  o  8:[0-9a-f]{12} c (re)
+  |
+  | x  7:[0-9a-f]{12} d (re)
+  | |
+  | x  6:[0-9a-f]{12} c (re)
+  |/
+  o  5:[0-9a-f]{12} (re)
+  
+  x  4:[0-9a-f]{12} a (re)
+  
+  o  3:[0-9a-f]{12} ab (re)
+  
+  x  2:[0-9a-f]{12} temporary amend commit for [0-9a-f]{12} (re)
+  |
+  x  1:[0-9a-f]{12} a (re)
+  
+  x  0:[0-9a-f]{12} a (re)
+  
+
   $ hg rebase -s 11 -d 12
-  rebasing 11:* "move" (glob)
+  rebasing 11:[0-9a-f]{12} "move" (re)
   $ hg st -C --change=tip
   A gna2
     gna1
--- a/tests/test-tutorial.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-tutorial.t	Wed Sep 27 01:12:47 2017 +0200
@@ -3,6 +3,7 @@
 -------------
 
 This Mercurial configuration example is used for testing.
+
 .. Various setup
 
   $ cat >> $HGRCPATH << EOF
@@ -64,6 +65,10 @@
   > rebase =
   > EOF
 
+#if docgraph-ext
+  $ . "$TESTDIR/testlib/docgraph_setup.sh" #rest-ignore
+#endif
+
 -----------------------
 Single Developer Usage
 -----------------------
@@ -124,6 +129,51 @@
   |
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	2	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=2,
+      		pin=true,
+      		pos="1,2!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 2	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 But a typo was made in Babanas!
 
@@ -158,7 +208,53 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-hopefully. I can use `hg commit --amend` to rewrite my faulty changeset!
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	2	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=2,
+      		pin=true,
+      		pos="1,2!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 2	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+Hopefully. I can use `hg commit --amend` to rewrite my faulty changeset!
 
   $ sed -i'' -e s/Bananos/Banana/ shopping
   $ hg diff
@@ -184,6 +280,52 @@
   |
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
   $ hg export tip
   # HG changeset patch
   # User test
@@ -207,7 +349,7 @@
 Getting rid of branchy history
 ----------------------------------
 
-While I was working on my list. someone made a change remotely.
+While I was working on my list. Someone made a change remotely.
 
   $ cd ../remote
   $ hg up -q
@@ -226,7 +368,7 @@
   added 1 changesets with 1 changes to 1 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
 
-I now have a new heads. Note that this remote head is immutable
+I now have a new head. Note that this remote head is immutable.
 
   $ hg log -G
   o  9ca060c80d74 (public): SPAM
@@ -238,7 +380,65 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-instead of merging my head with the new one. I'm going to rebase my work
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	1	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=1,
+      		pin=true,
+      		pos="1,1!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	0 -> 1	 [arrowhead=none,
+      		penwidth=2.0];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	4	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=4,
+      		pin=true,
+      		pos="1,4!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	1 -> 4	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+Instead of merging my head with the new one. I'm going to rebase my work
 
   $ hg diff
   $ hg rebase --dest 9ca060c80d74 --source 4d5dc8187023
@@ -259,11 +459,68 @@
   |
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 Removing changesets
 ------------------------
 
-I add new item to my list
+I add new items to my list.
 
   $ cat >> shopping << EOF
   > car
@@ -284,7 +541,7 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-I have a new commit but I realize that don't want it. (transport shop list does
+I have a new commit but I realize that don't want it. (Transport shop list does
 not fit well in my standard shopping list)
 
   $ hg prune . # "." is for working directory parent
@@ -304,6 +561,64 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
 Reordering changesets
 ------------------------
 
@@ -366,6 +681,88 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	9	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=9,
+      		pin=true,
+      		pos="1,9!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	7 -> 9	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
 We have a new SPAM SPAM version without the bathroom stuff
 
   $ grep Spam shopping  # enough spam
@@ -428,7 +825,87 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	12	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="1,12!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 12	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 Splitting change
 ------------------
@@ -513,7 +990,7 @@
 -----------------------
 
 
-sharing mutable changesets
+Sharing mutable changesets
 ----------------------------
 
 To share mutable changesets with others, just check that the repo you interact
@@ -524,7 +1001,7 @@
   $ hg -R ../local/ showconfig phases
   [1]
 
-the localrepo does not have any specific configuration for `phases.publish`. It
+The localrepo does not have any specific configuration for `phases.publish`. It
 is ``true`` by default.
 
   $ hg pull local
@@ -550,8 +1027,6 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-
-
 We do not want to publish the "bathroom changeset". Let's rollback the last transaction.
 
 .. Warning: Rollback is actually a dangerous kind of internal command that is deprecated and should not be exposed to user. Please forget you read about it until someone fix this tutorial.
@@ -570,7 +1045,7 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-Let's make the local repo "non publishing"
+Let's make the local repo "non publishing".
 
   $ echo '[phases]' >> ../local/.hg/hgrc
   $ echo 'publish=false' >> ../local/.hg/hgrc
@@ -641,6 +1116,87 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 When we pull from remote again we get an unstable state!
 
@@ -676,6 +1232,116 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	12	 [fillcolor="#DFDFFF",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=12,
+      		pin=true,
+      		pos="2,12!",
+      		shape=pentagon,
+      		style="dotted, filled",
+      		width=0.5];
+      	11 -> 12	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	12 -> 14	 [arrowhead=none,
+      		minlen=0,
+      		penwidth=2.0,
+      		style=dashed];
+      	15	 [fillcolor="#FF4F4F",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=15,
+      		pin=true,
+      		pos="2,15!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	12 -> 15	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
 The older version 75954b8cd933 never ceased to exist in the local repo. It was
 just hidden and excluded from pull and push.
 
@@ -692,8 +1358,6 @@
   [255]
  
 
-
-
 To resolve this unstable state, you need to rebase bf1b0d202029 onto
 a44c85f957d3. The `hg evolve` command will do this for you.
 
@@ -730,8 +1394,101 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	16	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="1,16!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	14 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
-We can push this evolution to remote
+We can push this evolution to remote.
 
   $ hg push remote
   pushing to $TESTTMP/remote (glob)
@@ -742,7 +1499,8 @@
   added 2 changesets with 2 changes to 1 files (+1 heads)
   3 new obsolescence markers
 
-remote get a warning that current working directory is based on an obsolete changeset
+Remote get a warning that current working directory is based on an obsolete
+changeset.
 
   $ cd ../remote
   $ hg pull local # we up again to trigger the warning. it was displayed during the push
@@ -752,7 +1510,7 @@
   working directory parent is obsolete! (bf1b0d202029)
   (use 'hg evolve' to update to its successor: ee942144f952)
 
-now let's see where we are, and update to the successor
+Now let's see where we are, and update to the successor.
 
   $ hg parents
   bf1b0d202029 (draft): animals
@@ -766,7 +1524,7 @@
 Relocating unstable change after prune
 ----------------------------------------------
 
-The remote guy keep working
+The remote guy keeps working.
 
   $ sed -i'' -e 's/Spam/Spam Spam Spam Spam/g' shopping
   $ hg commit -m "SPAM SPAM SPAM"
@@ -800,6 +1558,112 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	16	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="1,16!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	14 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      	17	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="1,17!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	16 -> 17	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
 In the mean time I noticed you can't buy animals in a super market and I prune the animal changeset:
 
   $ hg prune ee942144f952
@@ -810,7 +1674,7 @@
 
 
 The animals changeset is still displayed because the "SPAM SPAM SPAM" changeset
-is neither dead or obsolete.  My repository is in an unstable state again.
+is neither dead or obsolete. My repository is in an unstable state again.
 
   $ hg log -G
   o  99f039c5ec9e (draft): SPAM SPAM SPAM
@@ -830,9 +1694,137 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
-  $ hg log -r 'unstable()'
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	16	 [fillcolor="#DFDFFF",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=16,
+      		pin=true,
+      		pos="2,16!",
+      		shape=pentagon,
+      		style="dotted, filled",
+      		width=0.5];
+      	14 -> 16	 [arrowhead=none,
+      		penwidth=2.0];
+      	17	 [fillcolor="#FF4F4F",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="2,17!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	16 -> 17	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
+
+  $ hg log -r "unstable()"
   99f039c5ec9e (draft): SPAM SPAM SPAM
 
+#if docgraph-ext
+  $ hg docgraph -r "unstable()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	17	 [fillcolor="#FF4F4F",
+      		fixedsize=true,
+      		group=default_alt,
+      		height=0.5,
+      		label=17,
+      		pin=true,
+      		pos="1,17!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      }
+#endif
+
   $ hg evolve
   move:[17] SPAM SPAM SPAM
   atop:[14] bathroom stuff
@@ -855,6 +1847,99 @@
   o  7e82d3f3c2cb (public): Monthy Python Shopping list
   
 
+#if docgraph-ext
+  $ hg docgraph -r "all()" --sphinx-directive --rankdir LR #rest-ignore
+  .. graphviz::
+  
+      strict digraph  {
+      	graph [rankdir=LR,
+      		splines=polyline
+      	];
+      	node [label="\N"];
+      	0	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=0,
+      		pin=true,
+      		pos="1,0!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=5,
+      		pin=true,
+      		pos="1,5!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	0 -> 5	 [arrowhead=none,
+      		penwidth=2.0];
+      	6	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=6,
+      		pin=true,
+      		pos="1,6!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	5 -> 6	 [arrowhead=none,
+      		penwidth=2.0];
+      	7	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=7,
+      		pin=true,
+      		pos="1,7!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	6 -> 7	 [arrowhead=none,
+      		penwidth=2.0];
+      	11	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=11,
+      		pin=true,
+      		pos="1,11!",
+      		shape=circle,
+      		style=filled,
+      		width=0.5];
+      	7 -> 11	 [arrowhead=none,
+      		penwidth=2.0];
+      	14	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=14,
+      		pin=true,
+      		pos="1,14!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	11 -> 14	 [arrowhead=none,
+      		penwidth=2.0];
+      	18	 [fillcolor="#9999FF",
+      		fixedsize=true,
+      		group=default,
+      		height=0.5,
+      		label=18,
+      		pin=true,
+      		pos="1,18!",
+      		shape=pentagon,
+      		style=filled,
+      		width=0.5];
+      	14 -> 18	 [arrowhead=none,
+      		penwidth=2.0];
+      }
+#endif
 
 Handling Divergent amend
 ----------------------------------------------
--- a/tests/test-uncommit.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-uncommit.t	Wed Sep 27 01:12:47 2017 +0200
@@ -287,7 +287,7 @@
   $ hg up -C 3 --hidden
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   working directory parent is obsolete! (5eb72dbe0cb4)
-  (5eb72dbe0cb4 has diverged, use 'hg evolve --list --divergent' to resolve the issue)
+  (5eb72dbe0cb4 has diverged, use 'hg evolve --list --contentdivergent' to resolve the issue)
   $ hg --config extensions.purge= purge
   $ hg uncommit --all -X e
   1 new divergent changesets
--- a/tests/test-unstable.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-unstable.t	Wed Sep 27 01:12:47 2017 +0200
@@ -53,7 +53,7 @@
   o  0:135f39f4bd78@default(draft) add _a
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   move:[2] add _c
   atop:[3] bprime
   working directory is now at fdcf3523a74d
@@ -99,7 +99,7 @@
   o  0:b4952fcf48cf@default(draft) add base
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   move:[3] merge
   atop:[4] aprime
   working directory is now at 0bf3f3a59c8c
@@ -152,7 +152,7 @@
   o  0:b4952fcf48cf@default(draft) add base
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   warning: no support for evolving merge changesets with two obsolete parents yet
   (Redo the merge (6b4280e33286) and use `hg prune <old> --succ <new>` to obsolete the old one)
   $ hg log -G
@@ -198,7 +198,7 @@
   o  0:135f39f4bd78@default(draft) add _a
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   move:[2] add _c
   atop:[4] add bprimesplit2
   working directory is now at 387cc1e837d7
@@ -252,7 +252,7 @@
   o  0:135f39f4bd78@default(draft) add _a
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   move:[2] add _c
   atop:[6] add bsecondsplit2
   working directory is now at 98e3f21461ff
@@ -301,7 +301,7 @@
   o  0:135f39f4bd78@default(draft) add _a
   
 
-  $ hg evo --all --any --unstable
+  $ hg evo --all --any --orphan
   cannot solve split accross two branches
   $ hg log -G
   @  4:3c69ea6aa93e@default(draft) add bprimesplit2
--- a/tests/test-userguide.t	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/test-userguide.t	Wed Sep 27 01:12:47 2017 +0200
@@ -301,7 +301,7 @@
   $ hg status
   M file2.c
   $ hg commit -m 'useful tweak'
-  $ hg --hidden shortlog -G -r 25::
+  $ hg --hidden shortlog -G -r 0d972d6888e6::
   @  29:51e0d8c0a922  draft  useful tweak
   |
   o  28:2594e98553a9  draft  fix a bug
@@ -317,7 +317,7 @@
   move:[27] new feature
   atop:[28] fix a bug
   working directory is now at 166c1c368ab6
-  $ hg --hidden shortlog -G -r 25::
+  $ hg --hidden shortlog -G -r 0d972d6888e6::
   @  30:166c1c368ab6  draft  new feature
   |
   | o  29:51e0d8c0a922  draft  useful tweak
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testlib/docgraph_setup.sh	Wed Sep 27 01:12:47 2017 +0200
@@ -0,0 +1,6 @@
+. $TESTDIR/testlib/pythonpath.sh
+
+cat >> $HGRCPATH << EOF
+[extensions]
+docgraph=
+EOF
--- a/tests/testlib/topic_setup.sh	Tue Jul 25 15:17:42 2017 +0200
+++ b/tests/testlib/topic_setup.sh	Wed Sep 27 01:12:47 2017 +0200
@@ -1,4 +1,5 @@
 #!/bin/sh
+. $TESTDIR/testlib/pythonpath.sh
 
 # This file holds logic that is used in many tests.
 # It can be called in a test like this:
@@ -11,5 +12,5 @@
 
 [extensions]
 rebase=
+topic=
 EOF
-echo "topic=$(echo $(dirname $TESTDIR))/hgext3rd/topic" >> $HGRCPATH