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