changeset 1261:56cc2eb5995a stable

docs: add code review scenario to sharing guide The idea is to demonstrate a simpler multiple-developer situation that does not involve getting into trouble. The final scenario illustrates Alice and Bob getting into trouble with bumped and divergent changesets by amending each other's history. The required tests and text are all written, but will need to be heavily revised because of the inserted scenario.
author Greg Ward <greg@gerg.ca>
date Tue, 14 Apr 2015 12:53:12 -0400
parents e8016d1011b5
children eff1acc2511c
files docs/sharing.rst tests/test-sharing.t
diffstat 2 files changed, 464 insertions(+), 212 deletions(-) [+]
line wrap: on
line diff
--- a/docs/sharing.rst	Mon Jun 09 08:18:43 2014 -0400
+++ b/docs/sharing.rst	Tue Apr 14 12:53:12 2015 -0400
@@ -7,11 +7,10 @@
 .. contents::
 
 Once you have mastered the art of mutable history in a single
-repository (see the `user guide`_), you might want to move up to the
-next level: *shared* mutable history. ``evolve`` lets you push and
-pull draft changesets between repositories along with their
-obsolescence markers. This opens up a number of interesting
-possibilities.
+repository (see the `user guide`_), you can move up to the next level:
+*shared* mutable history. ``evolve`` lets you push and pull draft
+changesets between repositories along with their obsolescence markers.
+This opens up a number of interesting possibilities.
 
 .. _`user guide`: user-guide.html
 
@@ -38,8 +37,8 @@
 accidental ``rsync`` in the wrong direction could destroy hours of
 work.
 
-Using Mercurial with ``evolve`` to share mutable history solves all of
-these problems. As with single-repository ``evolve``, you can commit
+Using Mercurial with ``evolve`` to share mutable history solves these
+problems. As with single-repository ``evolve``, you can commit
 whenever the code is demonstrably better, even if all the tests aren't
 passing yet—just ``hg amend`` when they are. And you can transfer
 those half-baked changesets between repositories to try things out on
@@ -66,15 +65,15 @@
 Setting up
 ==========
 
-We'll work an example with three local repositories, although in the
-real world they'd most likely be on three different computers. First,
-the ``public`` repository is where tested, polished changesets live,
-and it is where you synchronize changesets with the rest of your team.
-::
+We'll work through an example with three local repositories, although
+in the real world they'd most likely be on three different computers.
+First, the ``public`` repository is where tested, polished changesets
+live, and it is where you synchronize with the rest of your team. ::
 
   $ hg init public
 
-We'll need two clones where work gets done::
+We'll need two clones where work gets done, ``test-repo`` and
+``dev-repo``::
 
   $ hg clone public test-repo
   updating to branch default
@@ -89,8 +88,9 @@
 we'll develop in ``dev-repo``, push to ``test-repo``, test and polish
 there, and push to ``public``.
 
-The key to shared mutable history is to make the target repository,
-``test-repo`` in this case, non-publishing. And, of course, we have to enable ``evolve`` in both ``test-repo`` and ``dev-repo``.
+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``.
 
 First, edit the configuration for ``test-repo``::
 
@@ -190,18 +190,21 @@
 we saw in the user guide)—but ``dev-repo`` knows nothing of these
 recent developments.
 
-  [figure SG02: rev 0:0dc9 public, rev 1:f649, 2:2a03 obsolete, rev 3:60ff draft -- but dev-repo same as in SG01]
+  [figure SG02: test-repo has rev 0:0dc9 public, rev 1:f649, 2:2a03 obsolete, rev 3:60ff draft; dev-repo same as in SG01]
 
 Let's resynchronize::
 
   $ cd ../dev-repo
   $ hg pull -u
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 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 obsolete. Push and pull
+the temporary amend commit, because it is hidden. Push and pull
 transfer obsolesence markers between repositories, but they do not
-normally transfer obsolete changesets.
+transfer hidden changesets.
 
   [figure SG03: dev-repo grows new rev 2:60ff, marks 1:f649 obsolete]
 
@@ -242,11 +245,8 @@
   added 1 changesets with 1 changes to 1 files
 
 Note that only one changeset—the final version, after two
-amendments—was actually pushed. Again, Mercurial normally doesn't
-transfer obsolete changesets on push and pull. (Specifically, it
-doesn't transfer *hidden* changesets: roughly speaking, obsolete
-changesets with no non-obsolete descendants. If you're curious, see
-the `concept guide`_ for the precise definition of hidden.)
+amendments—was actually pushed. Again, Mercurial doesn't transfer
+hidden changesets on push and pull.
 
 .. _`concept guide`: concepts.html
 
@@ -266,9 +266,228 @@
 
   $ cd ../dev-repo
   $ hg pull -u
+  [...]
+  no changes found
 
-Sharing with multiple developers
---------------------------------
+Even though no *changesets* were pulled, Mercurial still pulled
+obsolescence markers from ``test-repo``.
+
+Sharing with multiple developers: code review
+---------------------------------------------
+
+Now that you know how to share your own mutable history across
+multiple computers, you might be wondering if it makes sense to share
+mutable history with others. It does, but you have to be careful, stay
+alert, and *communicate* with your peers.
+
+A good way to start is with code review: Alice commits a draft
+changeset that Bob can review. Bob sends his comments to Alice, and
+she amends it until Bob is satisfied. Meanwhile, Bob is also
+committing draft changesets for Alice to review, amending until she is
+satisfied. Once a particular changeset passes review, the respective
+author (Alice or Bob) pushes it to the public repository.
+
+Setting up
+==========
+
+To demonstrate, let's start with the ``public`` repository as we left
+it in the last example, with two immutable changesets (figure 5
+above). We'll clone a ``review`` repository from it, and then Alice
+and Bob will both clone from ``review``. ::
+
+  $ hg clone public review
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg clone review alice
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg clone review bob
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+We need to configure Alice's and Bob's working repositories similar to
+``test-repo``, i.e. make them non-publishing and enable ``evolve``.
+First, edit Alice's configuration with ::
+
+  $ hg -R alice config --edit --local
+
+and add ::
+
+  [extensions]
+  evolve = /path/to/mutable-history/hgext/evolve.py
+
+Then add the same text to Bob's repository configuration::
+
+  $ hg -R bob config --edit --local
+
+Example 3: Alice commits and amends a draft fix
+===============================================
+
+We'll start by following Alice working on a bug fix. We're going to
+use bookmarks to make it easier to understand multiple branch heads in
+the ``review`` repository, so Alice starts off by creating a bookmark
+and committing her first attempt at a fix::
+
+  $ hg bookmark bug15
+  $ echo 'fix' > file2
+  $ hg commit -A -u alice -m 'fix bug 15 (v1)'
+  adding file2
+
+Note the unorthodox "(v1)" in the commit message. We're just using
+that to make this tutorial easier to follow; it's not something we'd
+recommend in real life.
+
+Of course Alice wouldn't commit unless her fix worked to her
+satisfaction, so it must be time to solicit a code review. She does
+this by pushing to the ``review`` repository::
+
+  $ hg push -B bug15
+  [...]
+  added 1 changesets with 1 changes to 1 files
+  exporting bookmark bug15
+
+(The use of ``-B`` is important to ensure that we only push the
+bookmarked head, and that the bookmark itself is pushed. See this
+`guide to bookmarks`_, especially the `Sharing Bookmarks`_ section, if
+you're not familiar with bookmarks.)
+
+.. _`guide to bookmarks`: http://mercurial.aragost.com/kick-start/en/bookmarks/
+.. _`Sharing Bookmarks`: http://mercurial.aragost.com/kick-start/en/bookmarks/#sharing-bookmarks
+
+Some time passes, and Alice receives her code review. (It might be by
+email, telephone, or carrier pigeon: it doesn't matter, as it's
+outside the scope of Mercurial.) As a result, Alice revises her fix
+and submits it for a second review::
+
+  $ echo 'Fix.' > file2
+  $ hg amend -m 'fix bug 15 (v2)'
+  $ hg push
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  updating bookmark bug15
+
+Figure 6 shows the state of the ``review`` repository at this point.
+
+  [figure SG06: rev 2:fn1e is alice's obsolete v1, rev 3:cbdf is her v2; both children of rev 1:de61]
+
+After a hard morning of bug fixing, Alice stops for lunch. Let's see
+what Bob has been up to.
+
+Example 4: Bob implements and publishes a new feature
+=====================================================
+
+In the meantime, Bob has been working on a new feature. Like Alice,
+he'll use a bookmark to track his work, and he'll push that bookmark
+to the ``review`` repository, so that reviewers know which changesets
+to review. ::
+
+  $ cd ../bob
+  $ echo 'stuff' > file1
+  $ hg bookmark featureX
+  $ hg commit -u bob -m 'implement feature X (v1)'
+  $ hg push -B featureX
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  exporting bookmark featureX
+
+When Bob receives his code review, he improves his implementation a
+bit, amends, and submits the resulting changeset for review::
+
+  $ echo 'do stuff' > file1
+  $ hg amend -m 'implement feature X (v2)'
+  $ hg push
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  updating bookmark featureX
+
+Unfortunately, that still doesn't pass muster. Bob's reviewer insists
+on proper capitalization and punctuation. ::
+
+  $ echo 'Do stuff.' > file1
+  $ hg amend -m 'implement feature X (v3)'
+
+On the bright side, the second review said, "Go ahead and publish once
+you fix that." So Bob immediately publishes his third attempt::
+
+  $ hg push ../public
+  [...]
+  added 1 changesets with 1 changes to 1 files
+
+Bob also has to update the ``review`` repository: right now it doesn't
+have his latest amendment ("v3", revision 6:540b), and it doesn't know
+that the precursor of that changeset ("v2", revision 5:0eb7) is
+obsolete. ::
+
+  $ hg push ../review
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  updating bookmark featureX
+
+Figure 7 shows the result of Bob's work in both ``review`` and
+``public``.
+
+  [figure SG07: review includes alice's draft work on bug 15, as well as Bob's v1, v2, and v3 changes for feature X: v1 and v2 obsolete, v3 public. public contains only the final, public implementation of feature X]
+
+Incidentally, it's important that Bob push to ``public`` *before*
+``review``. If he pushed to ``review`` first, then revision 6:540b
+would still be in *draft* phase in ``review``, but it would be
+*public* in both Bob's local repository and the ``public`` repository.
+That could lead to confusion at some point, which is easily avoided by
+pushing first to ``public``.
+
+Example 5: Alice integrates and publishes
+=========================================
+
+Finally, Alice gets back from lunch and sees that the carrier pigeon
+with her second review has arrived (or maybe she just has it in her
+email inbox). Alice's amended changeset has passed review, so she
+pushes her fix to ``public``::
+
+  $ hg push ../public
+  [...]
+  remote has heads on branch 'default' that are not known locally: 540ba8f317e6
+  abort: push creates new remote head cbdfbd5a5db2!
+  (pull and merge or see "hg help push" for details about pushing new heads)
+
+Oops! Bob has won the race to push first to ``public``. So Alice needs
+to integrate with Bob: let's pull his changeset(s) and see what the
+branch heads are. ::
+
+  $ hg pull ../public
+  [...]
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+  $ hg log -G -q -r 'head()' --template '{rev}:{node|short}  ({author})\n'
+  o  5:540ba8f317e6  (bob)
+  |
+  | @  4:cbdfbd5a5db2  (alice)
+  |/
+
+Since Alice and Bob are already using advanced technology in the form
+of shared mutable history, we'll assume they are perfectly comfortable
+with rebasing changesets. So Alice rebases her changeset on top of
+Bob's and publishes the result::
+
+  $ hg rebase -d 5
+  $ hg push ../public
+  [...]
+  added 1 changesets with 1 changes to 1 files
+  $ hg push ../review
+  [...]
+  added 1 changesets with 0 changes to 0 files
+  updating bookmark bug15
+
+The result, in both ``review`` and ``public`` repositories, is shown
+in figure 8.
+
+  [figure SG08: review shows v1 and v2 of alice's fix, then v1, v2, v3 of bob's feature, finally alice's fix rebased onto bob's. public just shows the final public version of each changeset]
+
+
+** STOP HERE: WORK IN PROGRESS **
+
+
+Getting into trouble with shared mutable history
+------------------------------------------------
 
 Mercurial with ``evolve`` is a powerful tool, and using powerful tools
 can have consequences. (You can cut yourself badly with a sharp knife,
@@ -283,31 +502,6 @@
 changesets. Both are more likely with shared mutable history,
 especially mutable history shared by multiple developers.
 
-Setting up
-==========
-
-To demonstrate, let's start with the ``public`` repository as we left
-it in the last example, with two immutable changesets (figure 5
-above). Two developers, Alice and Bob, start working from this point::
-
-  $ hg clone public alice
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg clone public bob
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-We need to configure Alice's and Bob's working repositories similar to
-``test-repo``, i.e. make them non-publishing and enable ``evolve``::
-
-  $ cat >> alice/.hg/hgrc <<EOF
-  [phases]
-  publish = false
-  [extensions]
-  evolve = /path/to/mutable-history/hgext/evolve.py
-  EOF
-  $ cp alice/.hg/hgrc bob/.hg/hgrc
-
 Bumped changesets: only one gets on the plane
 =============================================
 
--- a/tests/test-sharing.t	Mon Jun 09 08:18:43 2014 -0400
+++ b/tests/test-sharing.t	Tue Apr 14 12:53:12 2015 -0400
@@ -81,7 +81,16 @@
 Pull into dev-repo: obsolescence markers are transferred, but not
 the new obsolete changeset.
   $ cd ../dev-repo
-  $ hg pull -q -u
+  $ hg pull -u
+  pulling from $TESTTMP/test-repo
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pull obsolescence markers
+  2 obsolescence markers added
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 Figure SG03
   $ hg shortlog --hidden -G
@@ -144,220 +153,269 @@
   $ cd ../dev-repo
   $ hg shortlog -r 'draft()'
   4:de6151c48e1c  draft  fix bug 37
-  $ hg pull -q -u
+  $ hg pull -u
+  pulling from $TESTTMP/test-repo
+  searching for changes
+  no changes found
+  pull obsolescence markers
+  0 obsolescence markers added
   $ hg shortlog -r 'draft()'
 
-Sharing by Alice and Bob to demonstrate bumped and divergent changesets.
-First, setup repos for them.
+Sharing with multiple developers: code review
 
   $ cd ..
-  $ hg clone public alice
+  $ hg clone public review
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg clone public bob
+  $ hg clone review alice
   updating to branch default
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cat >> alice/.hg/hgrc <<EOF
+  $ hg clone review bob
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cat >> review/.hg/hgrc <<EOF
   > [phases]
   > publish = false
   > EOF
-  $ cp alice/.hg/hgrc bob/.hg/hgrc
 
-Alice commits a bug fix.
+Alice commits a draft bug fix, pushes to review repo.
   $ cd alice
+  $ hg bookmark bug15
   $ echo 'fix' > file2
-  $ hg commit -A -u alice -m 'fix bug 15'
+  $ hg commit -A -u alice -m 'fix bug 15 (v1)'
   adding file2
-
-Bob pulls and amends Alice's fix.
-  $ cd ../bob
-  $ hg pull -u ../alice
-  pulling from ../alice
+  $ hg push -B bug15
+  pushing to $TESTTMP/review
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
-  pull obsolescence markers
+  pushing 4 obsolescence markers (* bytes) (glob)
   0 obsolescence markers added
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  exporting bookmark bug15
+  $ hg -R ../review bookmarks
+     bug15                     2:f91e97234c2b
+
+Alice receives code review, amends her fix, and goes out to lunch to
+await second review.
   $ echo 'Fix.' > file2
-  $ hg amend -A -u bob -m 'fix bug 15 (amended)'
+  $ hg amend -m 'fix bug 15 (v2)'
+  $ hg push
+  pushing to $TESTTMP/review
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pushing 6 obsolescence markers (* bytes) (glob)
+  2 obsolescence markers added
+  updating bookmark bug15
+  $ hg -R ../review bookmarks
+     bug15                     3:cbdfbd5a5db2
 
-Figure SG06: Bob's repository after amending Alice's fix.
-(Nothing new here; we could have seen this in the user guide.
-  $ hg --hidden shortlog -G
-  @  4:fe884dfac355  draft  fix bug 15 (amended)
+Figure SG06: review repository after Alice pushes her amended changeset.
+  $ hg --hidden -R ../review shortlog -G -r 1::
+  o  3:cbdfbd5a5db2  draft  fix bug 15 (v2)
+  |
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
+  |/
+  @  1:de6151c48e1c  public  fix bug 37
   |
-  | x  3:0376cac226f8  draft  temporary amend commit for e011baf925da
-  | |
-  | x  2:e011baf925da  draft  fix bug 15
-  |/
-  o  1:de6151c48e1c  public  fix bug 37
-  |
-  o  0:0dc9c9f6ab91  public  create new project
-  
+
+Bob commits a draft changeset, pushes to review repo.
+  $ cd ../bob
+  $ echo 'stuff' > file1
+  $ hg bookmark featureX
+  $ hg commit -u bob -m 'implement feature X (v1)'
+  $ hg push -B featureX
+  pushing to $TESTTMP/review
+  searching for changes
+  remote has heads on branch 'default' that are not known locally: cbdfbd5a5db2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pushing 4 obsolescence markers (* bytes) (glob)
+  0 obsolescence markers added
+  exporting bookmark featureX
+  $ hg -R ../review bookmarks
+     bug15                     3:cbdfbd5a5db2
+     featureX                  4:193657d1e852
 
-But in the meantime, Alice decides the fix is just fine and publishes it.
-  $ cd ../alice
+Bob receives first review, amends and pushes.
+  $ echo 'do stuff' > file1
+  $ hg amend -m 'implement feature X (v2)'
   $ hg push
-  pushing to $TESTTMP/public
+  pushing to $TESTTMP/review
+  searching for changes
+  remote has heads on branch 'default' that are not known locally: cbdfbd5a5db2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pushing 6 obsolescence markers (* bytes) (glob)
+  2 obsolescence markers added
+  updating bookmark featureX
+
+Bob receives second review, amends, and pushes to public:
+this time, he's sure he got it right!
+  $ echo 'Do stuff.' > file1
+  $ hg amend -m 'implement feature X (v3)'
+  $ hg push ../public
+  pushing to ../public
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
-  pushing 4 obsolescence markers (369 bytes)
-  0 obsolescence markers added
-
-Which means that Bob now has an formerly obsolete changeset that is
-also public (2:6e83). As soon as he pulls its phase change, he's got
-trouble: the successors of that formerly obsolete changeset are
-bumped.
+  pushing 8 obsolescence markers (* bytes) (glob)
+  4 obsolescence markers added
+  $ hg -R ../public bookmarks
+  no bookmarks set
+  $ hg push ../review
+  pushing to ../review
+  searching for changes
+  remote has heads on branch 'default' that are not known locally: cbdfbd5a5db2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pushing 8 obsolescence markers (* bytes) (glob)
+  2 obsolescence markers added
+  updating bookmark featureX
+  $ hg -R ../review bookmarks
+     bug15                     3:cbdfbd5a5db2
+     featureX                  6:540ba8f317e6
 
-  $ cd ../bob
-  $ hg --hidden shortlog -r 'obsolete()'
-  2:e011baf925da  draft  fix bug 15
-  3:0376cac226f8  draft  temporary amend commit for e011baf925da
-  $ hg pull -q -u
-  1 new bumped changesets
-  $ hg --hidden shortlog -r 'obsolete()'
-  3:0376cac226f8  draft  temporary amend commit for e011baf925da
-  $ hg shortlog -r 'bumped()'
-  4:fe884dfac355  draft  fix bug 15 (amended)
+Figure SG07: review and public repos after Bob implements feature X.
+  $ hg --hidden -R ../review shortlog -G -r 1::
+  o  6:540ba8f317e6  public  implement feature X (v3)
+  |
+  | x  5:0eb74a7b6698  draft  implement feature X (v2)
+  |/
+  | x  4:193657d1e852  draft  implement feature X (v1)
+  |/
+  | o  3:cbdfbd5a5db2  draft  fix bug 15 (v2)
+  |/
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
+  |/
+  @  1:de6151c48e1c  public  fix bug 37
+  |
+  $ hg --hidden -R ../public shortlog -G -r 1::
+  o  2:540ba8f317e6  public  implement feature X (v3)
+  |
+  o  1:de6151c48e1c  public  fix bug 37
+  |
 
-Figure SG07: Bob's repo with one bumped changeset (rev 4:c02d)
-  $ hg --hidden shortlog -G
-  @  4:fe884dfac355  draft  fix bug 15 (amended)
+How do things look in the review repo?
+  $ cd ../review
+  $ hg --hidden shortlog -G -r 1::
+  o  6:540ba8f317e6  public  implement feature X (v3)
   |
-  | x  3:0376cac226f8  draft  temporary amend commit for e011baf925da
+  | x  5:0eb74a7b6698  draft  implement feature X (v2)
+  |/
+  | x  4:193657d1e852  draft  implement feature X (v1)
+  |/
+  | o  3:cbdfbd5a5db2  draft  fix bug 15 (v2)
+  |/
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
+  |/
+  @  1:de6151c48e1c  public  fix bug 37
+  |
+
+Meantime, Alice is back from lunch. While she was away, Bob approved
+her change, so now she can publish it.
+  $ cd ../alice
+  $ hg --hidden shortlog -G -r 1::
+  @  4:cbdfbd5a5db2  draft  fix bug 15 (v2)
+  |
+  | x  3:55dd95168a35  draft  temporary amend commit for f91e97234c2b
   | |
-  | o  2:e011baf925da  public  fix bug 15
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
   |/
   o  1:de6151c48e1c  public  fix bug 37
   |
-  o  0:0dc9c9f6ab91  public  create new project
-  
-
-Bob gets out of trouble by evolving the repository.
-  $ hg evolve --all
-  recreate:[4] fix bug 15 (amended)
-  atop:[2] fix bug 15
-  computing new diff
-  committed as 227d860d9ad0
-  working directory is now at 227d860d9ad0
-
-Figure SG08
-  $ hg --hidden shortlog -G
-  @  5:227d860d9ad0  draft  bumped update to e011baf925da:
+  $ hg outgoing -q ../public
+  4:cbdfbd5a5db2
+  $ hg push ../public
+  pushing to ../public
+  searching for changes
+  remote has heads on branch 'default' that are not known locally: 540ba8f317e6
+  abort: push creates new remote head cbdfbd5a5db2 with bookmark 'bug15'!
+  (pull and merge or see "hg help push" for details about pushing new heads)
+  [255]
+  $ hg pull ../public
+  pulling from ../public
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+  pull obsolescence markers
+  4 obsolescence markers added
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+  $ hg log -G -q -r 'head()'
+  o  5:540ba8f317e6
   |
-  | x  4:fe884dfac355  draft  fix bug 15 (amended)
+  | @  4:cbdfbd5a5db2
+  |/
+  $ hg --hidden shortlog -G -r 1::
+  o  5:540ba8f317e6  public  implement feature X (v3)
+  |
+  | @  4:cbdfbd5a5db2  draft  fix bug 15 (v2)
+  |/
+  | x  3:55dd95168a35  draft  temporary amend commit for f91e97234c2b
   | |
-  +---x  3:0376cac226f8  draft  temporary amend commit for e011baf925da
-  | |
-  o |  2:e011baf925da  public  fix bug 15
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
   |/
   o  1:de6151c48e1c  public  fix bug 37
   |
-  o  0:0dc9c9f6ab91  public  create new project
-  
 
-Throw away Bob's messy repo and start over.
-  $ cd ..
-  $ rm -rf bob
-  $ cp -rp alice bob
-
-Bob commits a pretty good fix that both he and Alice will amend,
-leading to divergence.
-  $ cd bob
-  $ echo 'pretty good fix' >> file1
-  $ hg commit -u bob -m 'fix bug 24 (v1)'
-
-Alice pulls Bob's fix and improves it.
-  $ cd ../alice
-  $ hg pull -u ../bob
-  pulling from ../bob
+Alice rebases her draft changeset on top of Bob's public changeset and
+publishes the result.
+  $ hg rebase -d 5
+  rebasing 4:cbdfbd5a5db2 "fix bug 15 (v2)" (bug15)
+  $ hg push ../public
+  pushing to ../public
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
-  pull obsolescence markers
-  0 obsolescence markers added
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ echo 'better (alice)' >> file1
-  $ hg amend -u alice -m 'fix bug 24 (v2 by alice)'
-
-Likewise, Bob amends his own fix. Now we have an obsolete changeset
-with two successors, although the successors are in different repos.
-  $ cd ../bob
-  $ echo 'better (bob)' >> file1
-  $ hg amend -u bob -m 'fix bug 24 (v2 by bob)'
+  pushing 11 obsolescence markers (* bytes) (glob)
+  3 obsolescence markers added
+  $ hg push ../review
+  pushing to ../review
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 0 changes to 1 files
+  pushing 11 obsolescence markers (* bytes) (glob)
+  1 obsolescence markers added
+  updating bookmark bug15
 
-Bob pulls from Alice's repo and discovers the trouble: divergent changesets!
-  $ hg pull -q -u ../alice
-  not updating: not a linear update
-  (merge or update --check to force update)
-  2 new divergent changesets
-  $ hg shortlog -r 'divergent()'
-  5:fc16901f4d7a  draft  fix bug 24 (v2 by bob)
-  6:694fd0f6b503  draft  fix bug 24 (v2 by alice)
-
-Figure SG09
-  $ hg --hidden shortlog -G
-  o  6:694fd0f6b503  draft  fix bug 24 (v2 by alice)
+Figure SG08: review and public changesets after Alice pushes.
+  $ hg --hidden -R ../review shortlog -G -r 1::
+  o  7:a06ec1bf97bd  public  fix bug 15 (v2)
+  |
+  o  6:540ba8f317e6  public  implement feature X (v3)
   |
-  | @  5:fc16901f4d7a  draft  fix bug 24 (v2 by bob)
+  | x  5:0eb74a7b6698  draft  implement feature X (v2)
+  |/
+  | x  4:193657d1e852  draft  implement feature X (v1)
+  |/
+  | x  3:cbdfbd5a5db2  draft  fix bug 15 (v2)
   |/
-  | x  4:162612d3335b  draft  temporary amend commit for fe81d904ed08
-  | |
-  | x  3:fe81d904ed08  draft  fix bug 24 (v1)
+  | x  2:f91e97234c2b  draft  fix bug 15 (v1)
   |/
-  o  2:e011baf925da  public  fix bug 15
+  @  1:de6151c48e1c  public  fix bug 37
+  |
+  $ hg --hidden -R ../public shortlog -G -r 1::
+  o  3:a06ec1bf97bd  public  fix bug 15 (v2)
+  |
+  o  2:540ba8f317e6  public  implement feature X (v3)
   |
   o  1:de6151c48e1c  public  fix bug 37
   |
-  o  0:0dc9c9f6ab91  public  create new project
-  
-Merge the trouble away.
-  $ hg merge --tool internal:local
-  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
-  (branch merge, don't forget to commit)
-  $ hg commit -m merge
-  $ hg shortlog -G
-  @    7:b1d30ba26e44  draft  merge
-  |\
-  | o  6:694fd0f6b503  draft  fix bug 24 (v2 by alice)
-  | |
-  o |  5:fc16901f4d7a  draft  fix bug 24 (v2 by bob)
-  |/
-  o  2:e011baf925da  public  fix bug 15
-  |
-  o  1:de6151c48e1c  public  fix bug 37
-  |
-  o  0:0dc9c9f6ab91  public  create new project
-  
-  $ hg log -q -r 'divergent()'
-  5:fc16901f4d7a
-  6:694fd0f6b503
-
-# XXX hg evolve does not solve this trouble! bug in evolve?
-#Evolve the trouble away.
-#  $ hg evolve --all --tool=internal:local
-#  merge:[5] fix bug 24 (v2 by bob)
-#  with: [6] fix bug 24 (v2 by alice)
-#  base: [3] fix bug 24 (v1)
-#  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
-#  $ hg status
-#  $ hg shortlog -G
-#  o  6:694fd0f6b503  draft  fix bug 24 (v2 by alice)
-#  |
-#  | @  5:fc16901f4d7a  draft  fix bug 24 (v2 by bob)
-#  |/
-#  o  2:e011baf925da  public  fix bug 15
-#  |
-#  o  1:de6151c48e1c  public  fix bug 37
-#  |
-#  o  0:0dc9c9f6ab91  public  create new project
-#  
-#  $ hg --hidden shortlog -G