|
1 .. Copyright © 2014 Greg Ward <greg@gerg.ca> |
|
2 |
|
3 ------------------ |
|
4 Evolve: User Guide |
|
5 ------------------ |
|
6 |
|
7 .. contents:: |
|
8 |
|
9 Life without ``evolve`` |
|
10 ----------------------- |
|
11 |
|
12 Before we dive into learning about ``evolve``, let's look into some |
|
13 features of core Mercurial that interact with ``evolve``. ``commit`` |
|
14 affects ``evolve``, and ``evolve`` modifies how ``commit --amend`` |
|
15 works. |
|
16 |
|
17 Example 1: Commit a new changeset |
|
18 ================================= |
|
19 |
|
20 To create a new changeset, simply run ``hg commit`` as usual. |
|
21 ``evolve`` does not change the behaviour of ``commit`` at all. |
|
22 |
|
23 However, it's important to understand that new changesets are in the |
|
24 *draft* phase by default: they are mutable. This means that they can |
|
25 be modified by Mercurial's existing history-editing commands |
|
26 (``rebase``, ``histedit``, etc.), and also by the ``evolve`` |
|
27 extension. Specifically, ``evolve`` adds a number of commands that can |
|
28 be used to modify history: ``amend``, ``uncommit``, ``prune``, |
|
29 ``fold``, and ``evolve``. Generally speaking, changesets remain in |
|
30 *draft* phase until they are pushed to another repository, at which |
|
31 point they enter *public* phase. :: |
|
32 |
|
33 $ hg commit -m 'implement feature X' |
|
34 $ hg phase -r . |
|
35 1: draft |
|
36 |
|
37 (Strictly speaking, changesets only become public when they are pushed |
|
38 to a *publishing* repository. But all repositories are publishing by |
|
39 default; you have to explicitly configure repositories to be |
|
40 *non-publishing*. Non-publishing repositories are an advanced topic |
|
41 which we'll see when we get to `sharing mutable history`_.) |
|
42 |
|
43 .. _`sharing mutable history`: sharing.html |
|
44 |
|
45 Example 2: Amend a changeset (traditional) |
|
46 ========================================== |
|
47 |
|
48 Imagine you've just committed a new changeset, and then you discover a |
|
49 mistake. Maybe you forgot to run the tests and a failure slipped in. |
|
50 You want to modify history so that you push one perfect changeset, |
|
51 rather than one flawed changeset followed by an "oops" commit. (Or |
|
52 perhaps you made a typo in the commit message—this is really feature |
|
53 *Y*, not feature X. You can't fix that with a followup commit.) |
|
54 |
|
55 This is actually trivial with plain vanilla Mercurial since 2.2: fix |
|
56 your mistake and run :: |
|
57 |
|
58 $ hg commit --amend -m 'implement feature Y' |
|
59 |
|
60 to create a new, amended changeset. The drawback of doing this with |
|
61 vanilla Mercurial is that your original, flawed, changeset is removed |
|
62 from the repository. This is *unsafe* history editing. It's probably |
|
63 not too serious if all you did was fix a syntax error, but still. |
|
64 |
|
65 .. figure:: figures/figure-ug01.svg |
|
66 |
|
67 Figure 1: unsafe history modification with core Mercurial (not |
|
68 using ``evolve``): the original revision 1 is destroyed. |
|
69 |
|
70 (Incidentally, Mercurial's traditional history modification mechanism |
|
71 isn't *really* unsafe: any changeset(s) removed from the repository |
|
72 are kept in a backup directory, so you can manually restore them later |
|
73 if you change your mind. But it's awkward and inconvenient compared to |
|
74 the features provided by ``evolve`` and changeset obsolescence.) |
|
75 |
|
76 Life with ``evolve`` (basic usage) |
|
77 ---------------------------------- |
|
78 |
|
79 Once you enable the ``evolve`` extension, a number of features are |
|
80 available to you. First, we're going to explore several examples of |
|
81 painless, trouble-free history modification. |
|
82 |
|
83 Example 3: Amend a changeset (with ``evolve``) |
|
84 ============================================== |
|
85 |
|
86 Outwardly, amending a changeset with ``evolve`` can look exactly the |
|
87 same as it does with core Mercurial (example 2):: |
|
88 |
|
89 $ hg commit --amend -m 'implement feature Y' |
|
90 |
|
91 Alternately, you can use the new ``amend`` command added by |
|
92 ``evolve``:: |
|
93 |
|
94 $ hg amend -m 'implement feature Y' |
|
95 |
|
96 (``hg amend`` is nearly synonymous with ``hg commit --amend``. The |
|
97 difference is that ``hg amend`` reuses the existing commit message by |
|
98 default, whereas ``hg commit --amend`` runs your editor if you don't |
|
99 pass ``-m`` or ``-l``.) |
|
100 |
|
101 Under the hood, though, things are quite different. Mercurial has |
|
102 simply marked the old changeset *obsolete*, replacing it with a new |
|
103 one. We'll explore what this means in detail later, after working |
|
104 through a few more examples. |
|
105 |
|
106 Example 4: Prune an unwanted changeset |
|
107 ====================================== |
|
108 |
|
109 Sometimes you make a change, and then decide it was such a bad idea |
|
110 that you don't want anyone to know about it. Or maybe it was a |
|
111 debugging hack that you needed to keep around for a while, but do not |
|
112 intend to ever push publicly. :: |
|
113 |
|
114 $ echo 'debug hack' >> file1.c |
|
115 $ hg commit -m 'debug hack' |
|
116 |
|
117 In either case, ``hg prune`` is the answer. ``prune`` simply marks |
|
118 changesets obsolete without creating any new changesets to replace |
|
119 them:: |
|
120 |
|
121 $ hg prune . |
|
122 1 changesets pruned |
|
123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
124 working directory now at 934359450037 |
|
125 |
|
126 Outwardly, it appears that your “debug hack” commit never happened; |
|
127 we're right back where we started:: |
|
128 |
|
129 $ hg parents --template '{rev}:{node|short} {desc|firstline}\n' |
|
130 3:934359450037 implement feature Y |
|
131 |
|
132 In reality, though, the “debug hack” is still there, obsolete and hidden. |
|
133 |
|
134 Example 5: Uncommit changes to certain files |
|
135 ============================================ |
|
136 |
|
137 Occasionally you commit more than you intended: perhaps you made |
|
138 unrelated changes to different files, and thus intend to commit |
|
139 different files separately. :: |
|
140 |
|
141 $ echo 'relevant' >> file1.c |
|
142 $ echo 'irrelevant' >> file2.c |
|
143 |
|
144 If you forget to specify filenames on the ``commit`` command line, |
|
145 Mercurial commits all those changes together:: |
|
146 |
|
147 $ hg commit -m 'fix bug 234' # oops: too many files |
|
148 |
|
149 Luckily, this mistake is easy to fix with ``uncommit``:: |
|
150 |
|
151 $ hg uncommit file2.c |
|
152 $ hg status |
|
153 M file2.c |
|
154 |
|
155 Let's verify that the replacement changeset looks right (i.e., |
|
156 modifies only ``file1.c``):: |
|
157 |
|
158 $ hg parents --template '{rev}:{node|short} {desc|firstline}\n{files}\n' |
|
159 6:c8defeecf7a4 fix bug 234 |
|
160 file1.c |
|
161 |
|
162 As before, the original flawed changeset is still there, but obsolete |
|
163 and hidden. It won't be exchanged with other repositories by ``push``, |
|
164 ``pull``, or ``clone``. |
|
165 |
|
166 Example 6: Fold multiple changesets together into one |
|
167 ===================================================== |
|
168 |
|
169 If you're making extensive changes to fragile source code, you might |
|
170 commit more frequently than normal so that you can fallback on a |
|
171 known good state if one step goes badly. :: |
|
172 |
|
173 $ echo step1 >> file1.c |
|
174 $ hg commit -m 'step 1' # revision 7 |
|
175 $ echo step2 >> file1.c |
|
176 $ hg commit -m 'step 2' # revision 8 |
|
177 $ echo step3 >> file2.c |
|
178 $ hg commit -m 'step 3' # revision 9 |
|
179 |
|
180 At the end of such a sequence, you often end up with a series of small |
|
181 changesets that are tedious to review individually. It might make more |
|
182 sense to combine them into a single changeset using the ``fold`` |
|
183 command. |
|
184 |
|
185 To make sure we pass the right revisions to ``fold``, let's review the |
|
186 changesets we just created, from revision 7:: |
|
187 |
|
188 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' -r 7:: |
|
189 7:05e61aab8294 step 1 |
|
190 8:be6d5bc8e4cc step 2 |
|
191 9:35f432d9f7c1 step 3 |
|
192 |
|
193 and fold them:: |
|
194 |
|
195 $ hg fold -m 'fix bug 64' -r 7:: |
|
196 3 changesets folded |
|
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
198 |
|
199 This time, Mercurial marks three changesets obsolete, replacing them |
|
200 all with a single *successor*. |
|
201 |
|
202 (You might be familiar with this operation under other names, like |
|
203 *squash* or *collapse*.) |
|
204 |
|
205 Changeset obsolescence under the hood |
|
206 ------------------------------------- |
|
207 |
|
208 So far, everything has gone just fine. We haven't run into merge |
|
209 conflicts or other trouble. Before we start exploring advanced usage |
|
210 that can run into trouble, let's step back and see what happens when |
|
211 Mercurial marks changesets obsolete. That will make it much easier to |
|
212 understand the more advanced use cases we'll see later. |
|
213 |
|
214 When you have the ``evolve`` extension enabled, all history |
|
215 modification uses the same underlying mechanism: the original |
|
216 changesets are marked *obsolete* and replaced by zero or more |
|
217 *successors*. The obsolete changesets are the *precursors* of their |
|
218 successors. This applies equally to built-in commands (``commit |
|
219 --amend``), commands added by ``evolve`` (``amend``, ``prune``, |
|
220 ``uncommit``, ``fold``), and even commands provided by other |
|
221 extensions (``rebase``, ``histedit``). |
|
222 |
|
223 Another way of looking at it is that obsolescence is second-order |
|
224 version control, i.e. the history of your history. We'll cover this in |
|
225 more detail (and mathematical precision) in the `concepts`_ guide. |
|
226 |
|
227 .. _`concepts`: concepts.html |
|
228 |
|
229 Under the hood: Amend a changeset |
|
230 ================================= |
|
231 |
|
232 Consider Example 2, amending a changeset with ``evolve``. We saw above |
|
233 that you can do this using the exact same command-line syntax as core |
|
234 Mercurial, namely ``hg commit --amend``. But the implementation is |
|
235 quite different, and Figure 2 shows how. |
|
236 |
|
237 .. figure:: figures/figure-ug02.svg |
|
238 |
|
239 Figure 2: safe history modification using ``evolve``: the original |
|
240 revision 1 is preserved as an obsolete changeset. (The "temporary |
|
241 amend commit", marked with T, is an implementation detail stemming |
|
242 from limitations in Mercurial's current merge machinery. Future |
|
243 versions of Mercurial will not create them.) |
|
244 |
|
245 In this case, the obsolete changesets are also *hidden*. That is the |
|
246 usual end state for obsolete changesets. But many scenarios result in |
|
247 obsolete changesets that are still visible, which indicates your |
|
248 history modification work is not yet done. We'll see examples of that |
|
249 later, when we cover advanced usage. |
|
250 |
|
251 Seeing hidden changesets |
|
252 ======================== |
|
253 |
|
254 TODO |
|
255 |
|
256 Under the hood: Prune an unwanted changeset |
|
257 =========================================== |
|
258 |
|
259 ``prune`` (example 4 above) is the simplest history modification |
|
260 command provided by ``evolve``. All it does is mark the specified |
|
261 changeset(s) obsolete, with no successor/precursor relationships |
|
262 involved. (If the working directory parent was one of the obsolete |
|
263 changesets, ``prune`` updates back to a suitable ancestor.) |
|
264 |
|
265 .. figure:: figures/figure-ug03.svg |
|
266 |
|
267 Figure 3: pruning a changeset marks it obsolete with no successors. |
|
268 |
|
269 Under the hood: Uncommit changes to certain files |
|
270 ================================================= |
|
271 |
|
272 In one sense, ``uncommit`` is a simplified version of ``amend``. Like |
|
273 ``amend``, it obsoletes one changeset and leaves it with a single |
|
274 successor. Unlike ``amend``, there is no ugly "temporary amend commit" |
|
275 cluttering up the repository. |
|
276 |
|
277 In another sense, ``uncommit`` is the inverse of ``amend``: ``amend`` |
|
278 takes any uncommitted changes in the working dir and “adds” |
|
279 them to the working directory's parent changeset. (In reality, of |
|
280 course, it creates a successor changeset, marking the original |
|
281 obsolete.) In contrast, ``uncommit`` takes some changes in the working |
|
282 directory's parent and moves them to the working dir, creating a new |
|
283 successor changeset in the process. Figure 4 illustrates. |
|
284 |
|
285 .. figure:: figures/figure-ug04.svg |
|
286 |
|
287 Figure 4: uncommit moves some of the changes from the working |
|
288 directory parent into the working dir, preserving the remaining |
|
289 changes as a new successor changeset. (N.B. revision 4 is not shown |
|
290 here because it was marked obsolete in the previous example.) |
|
291 |
|
292 |
|
293 Under the hood: Fold multiple changesets together into one |
|
294 ========================================================== |
|
295 |
|
296 The last basic example is folding multiple changesets into one, which |
|
297 marks multiple changesets obsolete, replacing them all with a single |
|
298 successor. |
|
299 |
|
300 .. figure:: figures/figure-ug05.svg |
|
301 |
|
302 Figure 5: fold combines multiple changesets into a single |
|
303 successor, marking the original (folded) changesets obsolete. |
|
304 |
|
305 |
|
306 Obsolete is not hidden |
|
307 ====================== |
|
308 |
|
309 TODO |
|
310 |
|
311 |
|
312 Understanding revision numbers |
|
313 ============================== |
|
314 |
|
315 If you're trying these examples on your own, especially using ``hg |
|
316 log`` without ``--hidden``, you have probably noticed some funny |
|
317 business going on with revision numbers: there are now gaps in the |
|
318 sequence. That's something you don't see with plain vanilla Mercurial; |
|
319 normally, revision N is always followed by revision N+1. |
|
320 |
|
321 This is just the visible manifestation of hidden changesets. If |
|
322 revision 95 is followed by revision 98, that means there are two |
|
323 hidden changesets, 96 and 97, in between. |
|
324 |
|
325 Note that changeset IDs are still the permanent, immutable identifier |
|
326 for changesets. Revision numbers are, as ever, a handy shorthand that |
|
327 work in your local repository, but cannot be used across repositories. |
|
328 They also have the useful property of showing when there are hidden |
|
329 changesets lurking under the covers, which is why this document uses |
|
330 revision numbers. |
|
331 |
|
332 |
|
333 Life with ``evolve`` (advanced usage) |
|
334 ------------------------------------- |
|
335 |
|
336 Now that you've got a solid understanding of how ``evolve`` works in |
|
337 concert with changeset obsolescence, let's explore some more advanced |
|
338 scenarios. All of these scenarios will involve *unstable* changesets, |
|
339 which is an unavoidable consequence of obsolescence. What really sets |
|
340 ``evolve`` apart from other history modification mechanisms is the |
|
341 fact that it recognizes troubles like unstable changesets and provides |
|
342 a consistent way for you to get out of trouble. |
|
343 |
|
344 (Incidentally, there are two other types of trouble that changesets |
|
345 can get into with ``evolve``: they may be *divergent* or *bumped*. |
|
346 Both of those states are more likely to occur when `sharing mutable |
|
347 history`_, so we won't see them in this user guide.) |
|
348 |
|
349 .. _`sharing mutable history`: sharing.html |
|
350 |
|
351 |
|
352 Example 7: Amend an older changeset |
|
353 =================================== |
|
354 |
|
355 Sometimes you don't notice your mistakes until after you have |
|
356 committed some new changesets on top of them. :: |
|
357 |
|
358 $ hg commit -m 'fix bug 17' # rev 11 (mistake here) |
|
359 $ hg commit -m 'cleanup' # rev 12 |
|
360 $ hg commit -m 'feature 23' # rev 13 |
|
361 |
|
362 Traditionally, your only option is to commit an "oops" changeset that |
|
363 fixes your mistake. That works, of course, but it makes you look bad: |
|
364 you made a mistake, and the record of that mistake is recorded in |
|
365 history for all eternity. (If the mistake was in the commit message, |
|
366 too bad.) |
|
367 |
|
368 More subtly, there now exist changesets that are *worse* than what |
|
369 came before—the code no longer builds, the tests don't pass, or |
|
370 similar. Anyone reviewing these patches will waste time noticing the |
|
371 error in the earlier patch, and then the correction later on. |
|
372 |
|
373 You can avoid all this by amending the bad changeset and *evolving* |
|
374 subsequent history. Here's how it works, assuming you have just |
|
375 committed revision 13 and noticed the mistake in revision 11:: |
|
376 |
|
377 $ hg update 11 |
|
378 [...fix mistake...] |
|
379 $ hg amend |
|
380 |
|
381 At this point, revision 11 is *obsolete* and revisions 12 and 13—the |
|
382 descendants of 11—are in a funny state: they are *unstable*. |
|
383 |
|
384 .. figure:: figures/figure-ug06.svg |
|
385 |
|
386 Figure 6: amending a changeset with descendants means the amended |
|
387 changeset is obsolete but remains visible; its non-obsolete |
|
388 descendants are *unstable*. The temporary amend commit, revision |
|
389 14, is hidden because it has no non-obsolete descendants. |
|
390 |
|
391 All non-obsolete descendants of an obsolete changeset are unstable. An |
|
392 interesting consequence of this is that revision 11 is still visible, |
|
393 even though it is obsolete. Obsolete changesets with non-obsolete |
|
394 descendants are not hidden. |
|
395 |
|
396 The fix is to *evolve* history:: |
|
397 |
|
398 $ hg evolve --all |
|
399 |
|
400 This is a separate step, not automatically part of ``hg amend``, |
|
401 because there might be conflicts. If your amended changeset modifies a |
|
402 file that one of its descendants also modified, Mercurial has to fire |
|
403 up your merge tool to resolve the conflict. More importantly, you have |
|
404 to switch contexts from "writing code" to "resolving conflicts". That |
|
405 can be an expensive context switch, so Mercurial lets you decide when |
|
406 to do it. |
|
407 |
|
408 The end state, after ``evolve`` finishes, is that the original |
|
409 revisions (11-13) are obsolete and hidden. Their successor revisions |
|
410 (15-17) replace them. |
|
411 |
|
412 .. figure:: figures/figure-ug07.svg |
|
413 |
|
414 Figure 7: evolve your repository (``hg evolve --all``) to take care |
|
415 of instability. Unstable changesets become obsolete, and are |
|
416 replaced by successors just like the amended changeset was. |
|
417 |
|
418 Example 8: Prune an older changeset |
|
419 =================================== |
|
420 |
|
421 Let's say you've just committed the following changesets:: |
|
422 |
|
423 $ hg commit -m 'useful work' # rev 18 |
|
424 $ hg commit -m 'debug hack' # rev 19 |
|
425 $ hg commit -m 'more work' # rev 20 |
|
426 |
|
427 You want to drop revision 19, but keep 18 and 20. No problem:: |
|
428 |
|
429 $ hg prune 19 |
|
430 1 changesets pruned |
|
431 1 new unstable changesets |
|
432 |
|
433 As above, this leaves your repository in a funny intermediate state: |
|
434 revision 20 is the non-obsolete descendant of obsolete revision 19. |
|
435 That is, revision 20 is unstable. |
|
436 |
|
437 .. figure:: figures/figure-ug08.svg |
|
438 |
|
439 Figure 8: ``hg prune`` marks a changeset obsolete without creating |
|
440 a successor. Just like with ``hg amend``, non-obsolete descendants |
|
441 of the pruned changeset are now unstable. |
|
442 |
|
443 As before, the solution to unstable changesets is to evolve your |
|
444 repository:: |
|
445 |
|
446 $ hg evolve --all |
|
447 |
|
448 This rebases revision 20 on top of 18 as the new revision 21, leaving |
|
449 19 and 20 obsolete and hidden: |
|
450 |
|
451 .. figure:: figures/figure-ug09.svg |
|
452 |
|
453 Figure 9: once again, ``hg evolve --all`` takes care of instability. |
|
454 |
|
455 Example 9: Uncommit files from an older changeset (discard changes) |
|
456 ======================================================================= |
|
457 |
|
458 As in example 5, let's say you accidentally commit some unrelated |
|
459 changes together. Unlike example 5, you don't notice your mistake |
|
460 immediately, but commit a new changeset on top of the bad one. :: |
|
461 |
|
462 $ echo 'this fixes bug 53' >> file1.c |
|
463 $ echo 'debug hack' >> file2.c |
|
464 $ hg commit -m 'fix bug 53' # rev 22 (oops) |
|
465 $ echo 'and this handles bug 67' >> file1.c |
|
466 $ hg commit -m 'fix bug 67' # rev 23 (fine) |
|
467 |
|
468 As with ``amend``, you need to travel back in time and repair revision |
|
469 22, leaving your changes to ``file2.c`` back in the working |
|
470 directory:: |
|
471 |
|
472 $ hg update 22 |
|
473 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
474 $ hg uncommit file2.c |
|
475 1 new unstable changesets |
|
476 $ hg status |
|
477 M file2.c |
|
478 |
|
479 Now your repository has unstable changesets, so you need to evolve it. |
|
480 But ``hg evolve`` requires a clean working directory to resolve merge |
|
481 conflicts, so you need to decide what to do with ``file2.c``. |
|
482 |
|
483 In this case, the change to ``file2.c`` was a temporary debugging |
|
484 hack, so we can discard it and immediately evolve the instability away:: |
|
485 |
|
486 $ hg revert file2.c |
|
487 $ hg evolve --all |
|
488 move:[23] fix bug 67 |
|
489 atop:[24] fix bug 53 |
|
490 |
|
491 Figure 10 illustrates the whole process. |
|
492 |
|
493 .. figure:: figures/figure-ug10.svg |
|
494 |
|
495 Figure 10: ``hg uncommit`` of a changeset with descendants results |
|
496 in instability *and* a dirty working directory, both of which must |
|
497 be dealt with. |
|
498 |
|
499 |
|
500 Example 10: Uncommit files to an older changeset (keep changes) |
|
501 =================================================================== |
|
502 |
|
503 This is very similar to example 9. The difference that this time, our |
|
504 change to ``file2.c`` is valuable enough to commit, making things a |
|
505 bit more complicated. The setup is nearly identical:: |
|
506 |
|
507 $ echo 'fix a bug' >> file1.c |
|
508 $ echo 'useful but unrelated' >> file2.c |
|
509 $ hg commit -u dan -d '11 0' -m 'fix a bug' # rev 26 (oops) |
|
510 $ echo 'new feature' >> file1.c |
|
511 $ hg commit -u dan -d '12 0' -m 'new feature' # rev 27 (fine) |
|
512 |
|
513 As before, we update back to the flawed changeset (this time, |
|
514 revision 26) and ``uncommit``, leaving uncommitted changes to |
|
515 ``file2.c`` in the working dir:: |
|
516 |
|
517 $ hg update -q 26 |
|
518 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
519 $ hg uncommit -q file2.c # obsoletes rev 26, creates rev 28 |
|
520 1 new unstable changesets |
|
521 $ hg status |
|
522 M file2.c |
|
523 |
|
524 This time, let's save that useful change before evolving:: |
|
525 |
|
526 $ hg commit -m 'useful tweak' # rev 29 |
|
527 |
|
528 Figure 11 shows the story so far: ``uncommit`` obsoleted revision 26 |
|
529 and created revision 28, the successor of 26. Then we committed |
|
530 revision 29, a child of 28. We still have to deal with the unstable |
|
531 revision 27. |
|
532 |
|
533 .. figure:: figures/figure-ug11.svg |
|
534 |
|
535 Figure 11: Uncommitting a file and then committing that change |
|
536 separately will soon result in a two-headed repository. |
|
537 |
|
538 This is where things get tricky. As usual when a repository has |
|
539 unstable changesets, we want to evolve it:: |
|
540 |
|
541 $ hg evolve --all |
|
542 |
|
543 The problem is that ``hg evolve`` rebases revision 27 onto revision |
|
544 28, creating 30 (the successor of 27). This is entirely logical: 27 |
|
545 was the child of 26, and 26's successor is 28. So of course 27's |
|
546 successor (30) should be the child of 26's successor (28). |
|
547 Unfortunately, that leaves us with a two-headed repository: |
|
548 |
|
549 .. figure:: figures/figure-ug12.svg |
|
550 |
|
551 Figure 12: ``evolve`` takes care of unstable changesets; it does |
|
552 not solve all the world's problems. |
|
553 |
|
554 As usual when faced with a two-headed repository, you can either merge |
|
555 or rebase. It's up to you. |
|
556 |
|
557 |
|
558 Example 11: Recover an obsolete changeset |
|
559 ========================================= |
|
560 |
|
561 TODO |