Mercurial > evolve
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 |