comparison docs/sharing.rst @ 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
comparison
equal deleted inserted replaced
1260:e8016d1011b5 1261:56cc2eb5995a
5 ------------------------------ 5 ------------------------------
6 6
7 .. contents:: 7 .. contents::
8 8
9 Once you have mastered the art of mutable history in a single 9 Once you have mastered the art of mutable history in a single
10 repository (see the `user guide`_), you might want to move up to the 10 repository (see the `user guide`_), you can move up to the next level:
11 next level: *shared* mutable history. ``evolve`` lets you push and 11 *shared* mutable history. ``evolve`` lets you push and pull draft
12 pull draft changesets between repositories along with their 12 changesets between repositories along with their obsolescence markers.
13 obsolescence markers. This opens up a number of interesting 13 This opens up a number of interesting possibilities.
14 possibilities.
15 14
16 .. _`user guide`: user-guide.html 15 .. _`user guide`: user-guide.html
17 16
18 The simplest scenario is a single developer working across two 17 The simplest scenario is a single developer working across two
19 computers. Say you're working on code that must be tested on a remote 18 computers. Say you're working on code that must be tested on a remote
36 than what came before.) The latter, avoiding version control entirely, 35 than what came before.) The latter, avoiding version control entirely,
37 means that you're walking a tightrope without a safety net. One 36 means that you're walking a tightrope without a safety net. One
38 accidental ``rsync`` in the wrong direction could destroy hours of 37 accidental ``rsync`` in the wrong direction could destroy hours of
39 work. 38 work.
40 39
41 Using Mercurial with ``evolve`` to share mutable history solves all of 40 Using Mercurial with ``evolve`` to share mutable history solves these
42 these problems. As with single-repository ``evolve``, you can commit 41 problems. As with single-repository ``evolve``, you can commit
43 whenever the code is demonstrably better, even if all the tests aren't 42 whenever the code is demonstrably better, even if all the tests aren't
44 passing yet—just ``hg amend`` when they are. And you can transfer 43 passing yet—just ``hg amend`` when they are. And you can transfer
45 those half-baked changesets between repositories to try things out on 44 those half-baked changesets between repositories to try things out on
46 your test server before anything is carved in stone. 45 your test server before anything is carved in stone.
47 46
64 follows.) 63 follows.)
65 64
66 Setting up 65 Setting up
67 ========== 66 ==========
68 67
69 We'll work an example with three local repositories, although in the 68 We'll work through an example with three local repositories, although
70 real world they'd most likely be on three different computers. First, 69 in the real world they'd most likely be on three different computers.
71 the ``public`` repository is where tested, polished changesets live, 70 First, the ``public`` repository is where tested, polished changesets
72 and it is where you synchronize changesets with the rest of your team. 71 live, and it is where you synchronize with the rest of your team. ::
73 ::
74 72
75 $ hg init public 73 $ hg init public
76 74
77 We'll need two clones where work gets done:: 75 We'll need two clones where work gets done, ``test-repo`` and
76 ``dev-repo``::
78 77
79 $ hg clone public test-repo 78 $ hg clone public test-repo
80 updating to branch default 79 updating to branch default
81 0 files updated, 0 files merged, 0 files removed, 0 files unresolved 80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 $ hg clone test-repo dev-repo 81 $ hg clone test-repo dev-repo
87 everything configured just the way you like it. ``test-repo`` is the 86 everything configured just the way you like it. ``test-repo`` is the
88 test server in a rack somewhere behind SSH. So for the most part, 87 test server in a rack somewhere behind SSH. So for the most part,
89 we'll develop in ``dev-repo``, push to ``test-repo``, test and polish 88 we'll develop in ``dev-repo``, push to ``test-repo``, test and polish
90 there, and push to ``public``. 89 there, and push to ``public``.
91 90
92 The key to shared mutable history is to make the target repository, 91 The key to shared mutable history is to make the target repository, in
93 ``test-repo`` in this case, non-publishing. And, of course, we have to enable ``evolve`` in both ``test-repo`` and ``dev-repo``. 92 this case ``test-repo``, non-publishing. And, of course, we have to
93 enable ``evolve`` in both ``test-repo`` and ``dev-repo``.
94 94
95 First, edit the configuration for ``test-repo``:: 95 First, edit the configuration for ``test-repo``::
96 96
97 $ hg -R test-repo config --edit --local 97 $ hg -R test-repo config --edit --local
98 98
188 obsolete in ``test-repo``, having been replaced by revision 3:60ff 188 obsolete in ``test-repo``, having been replaced by revision 3:60ff
189 (revision 2:2a03 is another one of those temporary amend commits that 189 (revision 2:2a03 is another one of those temporary amend commits that
190 we saw in the user guide)—but ``dev-repo`` knows nothing of these 190 we saw in the user guide)—but ``dev-repo`` knows nothing of these
191 recent developments. 191 recent developments.
192 192
193 [figure SG02: rev 0:0dc9 public, rev 1:f649, 2:2a03 obsolete, rev 3:60ff draft -- but dev-repo same as in SG01] 193 [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]
194 194
195 Let's resynchronize:: 195 Let's resynchronize::
196 196
197 $ cd ../dev-repo 197 $ cd ../dev-repo
198 $ hg pull -u 198 $ hg pull -u
199 [...]
200 added 1 changesets with 1 changes to 1 files (+1 heads)
201 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 202
200 As seen in figure 3, this transfers the new changeset *and* the 203 As seen in figure 3, this transfers the new changeset *and* the
201 obsolescence marker for revision 1. However, it does *not* transfer 204 obsolescence marker for revision 1. However, it does *not* transfer
202 the temporary amend commit, because it is obsolete. Push and pull 205 the temporary amend commit, because it is hidden. Push and pull
203 transfer obsolesence markers between repositories, but they do not 206 transfer obsolesence markers between repositories, but they do not
204 normally transfer obsolete changesets. 207 transfer hidden changesets.
205 208
206 [figure SG03: dev-repo grows new rev 2:60ff, marks 1:f649 obsolete] 209 [figure SG03: dev-repo grows new rev 2:60ff, marks 1:f649 obsolete]
207 210
208 Because of this deliberately incomplete synchronization, revision 211 Because of this deliberately incomplete synchronization, revision
209 numbers in ``test-repo`` and ``dev-repo`` are no longer consistent. We 212 numbers in ``test-repo`` and ``dev-repo`` are no longer consistent. We
240 $ hg push 243 $ hg push
241 [...] 244 [...]
242 added 1 changesets with 1 changes to 1 files 245 added 1 changesets with 1 changes to 1 files
243 246
244 Note that only one changeset—the final version, after two 247 Note that only one changeset—the final version, after two
245 amendments—was actually pushed. Again, Mercurial normally doesn't 248 amendments—was actually pushed. Again, Mercurial doesn't transfer
246 transfer obsolete changesets on push and pull. (Specifically, it 249 hidden changesets on push and pull.
247 doesn't transfer *hidden* changesets: roughly speaking, obsolete
248 changesets with no non-obsolete descendants. If you're curious, see
249 the `concept guide`_ for the precise definition of hidden.)
250 250
251 .. _`concept guide`: concepts.html 251 .. _`concept guide`: concepts.html
252 252
253 So the picture in ``public`` is much simpler than in either 253 So the picture in ``public`` is much simpler than in either
254 ``dev-repo`` or ``test-repo``. None of our missteps or amendments are 254 ``dev-repo`` or ``test-repo``. None of our missteps or amendments are
264 public. Let's avoid that situation for now by pulling from 264 public. Let's avoid that situation for now by pulling from
265 ``test-repo`` down to ``dev-repo``:: 265 ``test-repo`` down to ``dev-repo``::
266 266
267 $ cd ../dev-repo 267 $ cd ../dev-repo
268 $ hg pull -u 268 $ hg pull -u
269 269 [...]
270 Sharing with multiple developers 270 no changes found
271 -------------------------------- 271
272 Even though no *changesets* were pulled, Mercurial still pulled
273 obsolescence markers from ``test-repo``.
274
275 Sharing with multiple developers: code review
276 ---------------------------------------------
277
278 Now that you know how to share your own mutable history across
279 multiple computers, you might be wondering if it makes sense to share
280 mutable history with others. It does, but you have to be careful, stay
281 alert, and *communicate* with your peers.
282
283 A good way to start is with code review: Alice commits a draft
284 changeset that Bob can review. Bob sends his comments to Alice, and
285 she amends it until Bob is satisfied. Meanwhile, Bob is also
286 committing draft changesets for Alice to review, amending until she is
287 satisfied. Once a particular changeset passes review, the respective
288 author (Alice or Bob) pushes it to the public repository.
289
290 Setting up
291 ==========
292
293 To demonstrate, let's start with the ``public`` repository as we left
294 it in the last example, with two immutable changesets (figure 5
295 above). We'll clone a ``review`` repository from it, and then Alice
296 and Bob will both clone from ``review``. ::
297
298 $ hg clone public review
299 updating to branch default
300 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 $ hg clone review alice
302 updating to branch default
303 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 $ hg clone review bob
305 updating to branch default
306 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
307
308 We need to configure Alice's and Bob's working repositories similar to
309 ``test-repo``, i.e. make them non-publishing and enable ``evolve``.
310 First, edit Alice's configuration with ::
311
312 $ hg -R alice config --edit --local
313
314 and add ::
315
316 [extensions]
317 evolve = /path/to/mutable-history/hgext/evolve.py
318
319 Then add the same text to Bob's repository configuration::
320
321 $ hg -R bob config --edit --local
322
323 Example 3: Alice commits and amends a draft fix
324 ===============================================
325
326 We'll start by following Alice working on a bug fix. We're going to
327 use bookmarks to make it easier to understand multiple branch heads in
328 the ``review`` repository, so Alice starts off by creating a bookmark
329 and committing her first attempt at a fix::
330
331 $ hg bookmark bug15
332 $ echo 'fix' > file2
333 $ hg commit -A -u alice -m 'fix bug 15 (v1)'
334 adding file2
335
336 Note the unorthodox "(v1)" in the commit message. We're just using
337 that to make this tutorial easier to follow; it's not something we'd
338 recommend in real life.
339
340 Of course Alice wouldn't commit unless her fix worked to her
341 satisfaction, so it must be time to solicit a code review. She does
342 this by pushing to the ``review`` repository::
343
344 $ hg push -B bug15
345 [...]
346 added 1 changesets with 1 changes to 1 files
347 exporting bookmark bug15
348
349 (The use of ``-B`` is important to ensure that we only push the
350 bookmarked head, and that the bookmark itself is pushed. See this
351 `guide to bookmarks`_, especially the `Sharing Bookmarks`_ section, if
352 you're not familiar with bookmarks.)
353
354 .. _`guide to bookmarks`: http://mercurial.aragost.com/kick-start/en/bookmarks/
355 .. _`Sharing Bookmarks`: http://mercurial.aragost.com/kick-start/en/bookmarks/#sharing-bookmarks
356
357 Some time passes, and Alice receives her code review. (It might be by
358 email, telephone, or carrier pigeon: it doesn't matter, as it's
359 outside the scope of Mercurial.) As a result, Alice revises her fix
360 and submits it for a second review::
361
362 $ echo 'Fix.' > file2
363 $ hg amend -m 'fix bug 15 (v2)'
364 $ hg push
365 [...]
366 added 1 changesets with 1 changes to 1 files (+1 heads)
367 updating bookmark bug15
368
369 Figure 6 shows the state of the ``review`` repository at this point.
370
371 [figure SG06: rev 2:fn1e is alice's obsolete v1, rev 3:cbdf is her v2; both children of rev 1:de61]
372
373 After a hard morning of bug fixing, Alice stops for lunch. Let's see
374 what Bob has been up to.
375
376 Example 4: Bob implements and publishes a new feature
377 =====================================================
378
379 In the meantime, Bob has been working on a new feature. Like Alice,
380 he'll use a bookmark to track his work, and he'll push that bookmark
381 to the ``review`` repository, so that reviewers know which changesets
382 to review. ::
383
384 $ cd ../bob
385 $ echo 'stuff' > file1
386 $ hg bookmark featureX
387 $ hg commit -u bob -m 'implement feature X (v1)'
388 $ hg push -B featureX
389 [...]
390 added 1 changesets with 1 changes to 1 files (+1 heads)
391 exporting bookmark featureX
392
393 When Bob receives his code review, he improves his implementation a
394 bit, amends, and submits the resulting changeset for review::
395
396 $ echo 'do stuff' > file1
397 $ hg amend -m 'implement feature X (v2)'
398 $ hg push
399 [...]
400 added 1 changesets with 1 changes to 1 files (+1 heads)
401 updating bookmark featureX
402
403 Unfortunately, that still doesn't pass muster. Bob's reviewer insists
404 on proper capitalization and punctuation. ::
405
406 $ echo 'Do stuff.' > file1
407 $ hg amend -m 'implement feature X (v3)'
408
409 On the bright side, the second review said, "Go ahead and publish once
410 you fix that." So Bob immediately publishes his third attempt::
411
412 $ hg push ../public
413 [...]
414 added 1 changesets with 1 changes to 1 files
415
416 Bob also has to update the ``review`` repository: right now it doesn't
417 have his latest amendment ("v3", revision 6:540b), and it doesn't know
418 that the precursor of that changeset ("v2", revision 5:0eb7) is
419 obsolete. ::
420
421 $ hg push ../review
422 [...]
423 added 1 changesets with 1 changes to 1 files (+1 heads)
424 updating bookmark featureX
425
426 Figure 7 shows the result of Bob's work in both ``review`` and
427 ``public``.
428
429 [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]
430
431 Incidentally, it's important that Bob push to ``public`` *before*
432 ``review``. If he pushed to ``review`` first, then revision 6:540b
433 would still be in *draft* phase in ``review``, but it would be
434 *public* in both Bob's local repository and the ``public`` repository.
435 That could lead to confusion at some point, which is easily avoided by
436 pushing first to ``public``.
437
438 Example 5: Alice integrates and publishes
439 =========================================
440
441 Finally, Alice gets back from lunch and sees that the carrier pigeon
442 with her second review has arrived (or maybe she just has it in her
443 email inbox). Alice's amended changeset has passed review, so she
444 pushes her fix to ``public``::
445
446 $ hg push ../public
447 [...]
448 remote has heads on branch 'default' that are not known locally: 540ba8f317e6
449 abort: push creates new remote head cbdfbd5a5db2!
450 (pull and merge or see "hg help push" for details about pushing new heads)
451
452 Oops! Bob has won the race to push first to ``public``. So Alice needs
453 to integrate with Bob: let's pull his changeset(s) and see what the
454 branch heads are. ::
455
456 $ hg pull ../public
457 [...]
458 added 1 changesets with 1 changes to 1 files (+1 heads)
459 (run 'hg heads' to see heads, 'hg merge' to merge)
460 $ hg log -G -q -r 'head()' --template '{rev}:{node|short} ({author})\n'
461 o 5:540ba8f317e6 (bob)
462 |
463 | @ 4:cbdfbd5a5db2 (alice)
464 |/
465
466 Since Alice and Bob are already using advanced technology in the form
467 of shared mutable history, we'll assume they are perfectly comfortable
468 with rebasing changesets. So Alice rebases her changeset on top of
469 Bob's and publishes the result::
470
471 $ hg rebase -d 5
472 $ hg push ../public
473 [...]
474 added 1 changesets with 1 changes to 1 files
475 $ hg push ../review
476 [...]
477 added 1 changesets with 0 changes to 0 files
478 updating bookmark bug15
479
480 The result, in both ``review`` and ``public`` repositories, is shown
481 in figure 8.
482
483 [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]
484
485
486 ** STOP HERE: WORK IN PROGRESS **
487
488
489 Getting into trouble with shared mutable history
490 ------------------------------------------------
272 491
273 Mercurial with ``evolve`` is a powerful tool, and using powerful tools 492 Mercurial with ``evolve`` is a powerful tool, and using powerful tools
274 can have consequences. (You can cut yourself badly with a sharp knife, 493 can have consequences. (You can cut yourself badly with a sharp knife,
275 but every competent chef keeps several around. Ever try to chop onions 494 but every competent chef keeps several around. Ever try to chop onions
276 with a spoon?) 495 with a spoon?)
280 non-obsolete changeset with obsolete ancestors is unstable.) 499 non-obsolete changeset with obsolete ancestors is unstable.)
281 500
282 Two other types of trouble can crop up: *bumped* and *divergent* 501 Two other types of trouble can crop up: *bumped* and *divergent*
283 changesets. Both are more likely with shared mutable history, 502 changesets. Both are more likely with shared mutable history,
284 especially mutable history shared by multiple developers. 503 especially mutable history shared by multiple developers.
285
286 Setting up
287 ==========
288
289 To demonstrate, let's start with the ``public`` repository as we left
290 it in the last example, with two immutable changesets (figure 5
291 above). Two developers, Alice and Bob, start working from this point::
292
293 $ hg clone public alice
294 updating to branch default
295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 $ hg clone public bob
297 updating to branch default
298 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
299
300 We need to configure Alice's and Bob's working repositories similar to
301 ``test-repo``, i.e. make them non-publishing and enable ``evolve``::
302
303 $ cat >> alice/.hg/hgrc <<EOF
304 [phases]
305 publish = false
306 [extensions]
307 evolve = /path/to/mutable-history/hgext/evolve.py
308 EOF
309 $ cp alice/.hg/hgrc bob/.hg/hgrc
310 504
311 Bumped changesets: only one gets on the plane 505 Bumped changesets: only one gets on the plane
312 ============================================= 506 =============================================
313 507
314 If two people show up at the airport with tickets for the same seat on 508 If two people show up at the airport with tickets for the same seat on