# HG changeset patch # User Greg Ward # Date 1429030693 14400 # Node ID 14f91037d2f6afb199d2212c391ea6aced389d16 # Parent 33ed6119a0bec7168c06f55380170e97561f3ece docs: revive the explanation of divergent changesets in the sharing guide diff -r 33ed6119a0be -r 14f91037d2f6 docs/sharing.rst --- a/docs/sharing.rst Fri Jun 20 08:19:04 2014 -0400 +++ b/docs/sharing.rst Tue Apr 14 12:58:13 2015 -0400 @@ -500,10 +500,6 @@ [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 ------------------------------------------------ @@ -516,10 +512,119 @@ the most common type of troubled changeset. (Recall that a non-obsolete changeset with obsolete ancestors is unstable.) -Two other types of trouble can crop up: *bumped* and *divergent* +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. +Setting up +========== + +For these examples, we're going to use a slightly different workflow: +as before, Alice and Bob share a ``public`` repository. But this time +there is no ``review`` repository. Instead, Alice and Bob put on their +cowboy hats, throw good practice to the wind, and pull directly from +each other's working repositories. + +So we throw away everything except ``public`` and reclone:: + + $ rm -rf review alice bob + $ hg clone public alice + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg clone public bob + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Once again we have to configure their repositories: enable ``evolve`` +and (since Alice and Bob will be pulling directly from each other) +make their repositories non-publishing. Edit Alice's configuration:: + + $ hg -R alice config --edit --local + +and add :: + + [extensions] + rebase = + evolve = /path/to/mutable-history/hgext/evolve.py + + [phases] + publish = false + +Then edit Bob's repository configuration:: + + $ hg -R bob config --edit --local + +and add the same text. + +Example 6: Divergent changesets +=============================== + +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. + +First, we'll have Bob commit a bug fix that could still be improved:: + + $ cd bob + $ echo 'pretty good fix' >> file1 + $ hg commit -u bob -m 'fix bug 24 (v1)' # rev 4:2fe6 + +Since Alice and Bob are now in cowboy mode, Alice pulls Bob's draft +changeset and amends it herself. :: + + $ cd ../alice + $ hg pull -u ../bob + [...] + added 1 changesets with 1 changes to 1 files + $ echo 'better fix (alice)' >> file1 + $ hg amend -u alice -m 'fix bug 24 (v2 by alice)' + +But Bob has no idea that Alice just did this. (See how important good +communication is?) So he implements a better fix of his own:: + + $ cd ../bob + $ echo 'better fix (bob)' >> file1 + $ hg amend -u bob -m 'fix bug 24 (v2 by bob)' # rev 6:a360 + +At this point, the divergence exists, but only in theory: Bob's +original changeset, 4:2fe6, is obsolete and has two successors. But +those successors are in different repositories, so the trouble is not +visible to anyone yet. It will be as soon as Bob pulls from Alice's +repository (or vice-versa). :: + + $ hg pull ../alice + [...] + added 1 changesets with 1 changes to 2 files (+1 heads) + (run 'hg heads' to see heads, 'hg merge' to merge) + 2 new divergent changesets + +Figure 9 shows the situation in Bob's repository. + + [figure SG09: Bob's repo with 2 heads for the 2 divergent changesets, 6:a360 and 7:e3f9; wc is at 6:a360; both are successors of obsolete 4:2fe6, hence divergence] + +Now we need to get out of trouble. As usual, the answer is to evolve +history. :: + + $ HGMERGE=internal:other hg evolve + merge:[6] fix bug 24 (v2 by bob) + with: [7] fix bug 24 (v2 by alice) + base: [4] fix bug 24 (v1) + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + +Figure 10 shows how Bob's repository looks now. + + [figure SG10: only one visible head, 9:5ad6, successor to hidden 6:a360 and 7:e3f9] + +We carefully dodged a merge conflict by specifying a merge tool +(``internal:other``) that will take Alice's changes over Bob's. (You +might wonder why Bob wouldn't prefer his own changes by using +``internal:local``. He's avoiding a `bug`_ in ``evolve`` that occurs +when evolving divergent changesets using ``internal:local``.) + +.. _`bug`: https://bitbucket.org/marmoute/mutable-history/issue/48/ + +** STOP HERE: WORK IN PROGRESS ** + Bumped changesets: only one gets on the plane ============================================= @@ -604,84 +709,6 @@ [figure SG08: 5:227d is new, formerly bumped changeset 4:fe88 now hidden] -Divergent changesets -==================== - -In addition to *unstable* and *bumped*, there is a third kind of -troubled changeset: *divergent*. When an obsolete changeset has two -successors, those successors are divergent. - -To illustrate, let's start Alice and Bob at the same -point—specifically, the point where Alice's repository currently -stands. Bob's repository is a bit of a mess, so we'll throw it away -and start him off with a copy of Alice's repository:: - - $ cd .. - $ rm -rf bob - $ cp -rp alice bob - -Now we'll have Bob commit a bug fix that could still be improved:: - - $ cd bob - $ echo 'pretty good fix' >> file1 - $ hg commit -u bob -m 'fix bug 24 (v1)' - -This time, Alice meddles with her colleague's work (still a bad -idea):: - - $ cd ../alice - $ hg pull -u ../bob - [...] - added 1 changesets with 1 changes to 1 files - $ echo 'better (alice)' >> file1 - $ hg amend -u alice -m 'fix bug 24 (v2 by alice)' - -Here's where things change from the "bumped" scenario above: this -time, the original author (Bob) decides to amend his changeset too. :: - - $ cd ../bob - $ echo 'better (bob)' >> file1 - $ hg amend -u bob -m 'fix bug 24 (v2 by bob)' - -At this point, the divergence exists, but only in theory: Bob's -original changeset, 3:fe81, is obsolete and has two successors. But -those successors are in different repositories, so the trouble is not -visible to anyone yet. It will be as soon as one of our players pulls -from the other's repository. Let's make Bob the victim again:: - - $ hg pull -q -u ../alice - not updating: not a linear update - (merge or update --check to force update) - 2 new divergent changesets - -The “not a linear update” is our first hint that something is wrong, -but of course “2 new divergent changesets” is the real problem. Figure -9 shows both problems. - - [figure SG09: Bob's repo with 2 heads for the 2 divergent changesets, 5:fc16 and 6:694f; wc is at 5:fc16, hence update refused; both are successors of obsolete 3:fe81, hence divergence] - -Now we need to get out of trouble. Unfortunately, a `bug`_ in -``evolve`` means that the usual answer (run ``hg evolve --all``) does -not work. Bob has to figure out the solution on his own: in this case, -merge. To avoid distractions, we'll set ``HGMERGE`` to make Mercurial -resolve any conflicts in favour of Bob. :: - - $ HGMERGE=internal:local hg merge - $ hg commit -m merge - -.. _`bug`: https://bitbucket.org/marmoute/mutable-history/issue/48/ - -This is approximately what ``hg evolve`` would do in this -circumstance, if not for that bug. One annoying difference is that -Mercurial thinks the two divergent changesets are still divergent, -which you can see with a simple revset query:: - - $ hg log -q -r 'divergent()' - 5:fc16901f4d7a - 6:694fd0f6b503 - -(That annoyance should go away when the bug is fixed.) - Conclusion ---------- diff -r 33ed6119a0be -r 14f91037d2f6 tests/test-sharing.t --- a/tests/test-sharing.t Fri Jun 20 08:19:04 2014 -0400 +++ b/tests/test-sharing.t Tue Apr 14 12:58:13 2015 -0400 @@ -424,3 +424,121 @@ | o 1:de6151c48e1c public fix bug 37 | + $ cd .. + +Setup for "cowboy mode" shared mutable history (to illustrate divergent +and bumped changesets). + $ rm -rf review alice bob + $ hg clone public alice + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg clone public bob + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat >> alice/.hg/hgrc < [phases] + > publish = false + > EOF + $ cp alice/.hg/hgrc bob/.hg/hgrc + +Now we'll have Bob commit a bug fix that could still be improved:: + + $ cd bob + $ echo 'pretty good fix' >> file1 + $ hg commit -u bob -m 'fix bug 24 (v1)' + $ hg shortlog -r . + 4:2fe6c4bd32d0 draft fix bug 24 (v1) + +Since Alice and Bob are now in cowboy mode, Alice pulls Bob's draft +changeset and amends it herself. :: + + $ cd ../alice + $ hg pull -u ../bob + pulling from ../bob + 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 fix (alice)' >> file1 + $ hg amend -u alice -m 'fix bug 24 (v2 by alice)' + +Bob implements a better fix of his own:: + + $ cd ../bob + $ echo 'better fix (bob)' >> file1 + $ hg amend -u bob -m 'fix bug 24 (v2 by bob)' + $ hg --hidden shortlog -G -r 3:: + @ 6:a360947f6faf draft fix bug 24 (v2 by bob) + | + | x 5:3466c7f5a149 draft temporary amend commit for 2fe6c4bd32d0 + | | + | x 4:2fe6c4bd32d0 draft fix bug 24 (v1) + |/ + o 3:a06ec1bf97bd public fix bug 15 (v2) + | + +Bob discovers the divergence. + $ hg pull ../alice + pulling from ../alice + 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 + (run 'hg heads' to see heads, 'hg merge' to merge) + 2 new divergent changesets + +Figure SG09: multiple heads! divergence! oh my! + $ hg --hidden shortlog -G -r 3:: + o 7:e3f99ce9d9cd draft fix bug 24 (v2 by alice) + | + | @ 6:a360947f6faf draft fix bug 24 (v2 by bob) + |/ + | x 5:3466c7f5a149 draft temporary amend commit for 2fe6c4bd32d0 + | | + | x 4:2fe6c4bd32d0 draft fix bug 24 (v1) + |/ + o 3:a06ec1bf97bd public fix bug 15 (v2) + | + $ hg --hidden shortlog -r 'successors(2fe6)' + 6:a360947f6faf draft fix bug 24 (v2 by bob) + 7:e3f99ce9d9cd draft fix bug 24 (v2 by alice) + +Use evolve to fix the divergence. + $ HGMERGE=internal:other hg evolve + merge:[6] fix bug 24 (v2 by bob) + with: [7] fix bug 24 (v2 by alice) + base: [4] fix bug 24 (v1) + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + working directory is now at 5ad6037c046c + $ hg log -q -r 'divergent()' + +Figure SG10: Bob's repository after fixing divergence. + $ hg --hidden shortlog -G -r 3:: + @ 9:5ad6037c046c draft fix bug 24 (v2 by bob) + | + | x 8:bcfc9a755ac3 draft temporary amend commit for a360947f6faf + | | + +---x 7:e3f99ce9d9cd draft fix bug 24 (v2 by alice) + | | + | x 6:a360947f6faf draft fix bug 24 (v2 by bob) + |/ + | x 5:3466c7f5a149 draft temporary amend commit for 2fe6c4bd32d0 + | | + | x 4:2fe6c4bd32d0 draft fix bug 24 (v1) + |/ + o 3:a06ec1bf97bd public fix bug 15 (v2) + | + $ hg --hidden shortlog -r 'precursors(9)' + 6:a360947f6faf draft fix bug 24 (v2 by bob) + 7:e3f99ce9d9cd draft fix bug 24 (v2 by alice) + $ cat file1 + Do stuff. + pretty good fix + better fix (alice)