author | Pierre-Yves David <pierre-yves.david@octobus.net> |
Fri, 14 Jul 2017 00:58:14 +0200 | |
changeset 2734 | 39c3b2b5deb0 |
parent 1270 | 0683e3030316 |
child 2931 | 83d2c9637e89 |
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``, |
|
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 |
||
1267
8cc6e90354a9
docs: tweak wording, punctuation for better readability
Greg Ward <greg@gerg.ca>
parents:
978
diff
changeset
|
208 |
So far, everything has gone just fine: we haven't run into merge |
978 | 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``, |
|
1267
8cc6e90354a9
docs: tweak wording, punctuation for better readability
Greg Ward <greg@gerg.ca>
parents:
978
diff
changeset
|
220 |
``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
|
221 |
(``rebase``, ``histedit``). |
978 | 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 |
||
1268 | 251 |
|
252 |
Understanding revision numbers and hidden changesets |
|
253 |
==================================================== |
|
254 |
||
255 |
As the name implies, hidden changesets are normally not visible. If |
|
256 |
you run ``hg log`` on the repository from Figure 2, Mercurial will |
|
257 |
show revisions 0 and 3, but not 1 and 2. That's something you don't |
|
258 |
see with plain vanilla Mercurial—normally, revision *N* is always |
|
259 |
followed by revision *N* + 1. |
|
260 |
||
261 |
This is just the visible manifestation of hidden changesets. If |
|
262 |
revision 0 is followed by revision 3, that means there are two hidden |
|
263 |
changesets, 1 and 2, in between. |
|
264 |
||
265 |
To see those hidden changesets, use the ``--hidden`` option:: |
|
978 | 266 |
|
1268 | 267 |
$ hg --hidden log --graph --template '{rev}:{node|short} {desc|firstline}\n' |
268 |
@ 3:934359450037 implement feature Y |
|
269 |
| |
|
270 |
| x 2:6c5f78d5d467 temporary amend commit for fe0ecd3bd2a4 |
|
271 |
| | |
|
272 |
| x 1:fe0ecd3bd2a4 implement feature Y |
|
273 |
|/ |
|
274 |
o 0:08c4b6f4efc8 init |
|
275 |
||
276 |
Note that changeset IDs are still the permanent, immutable identifier |
|
277 |
for changesets. Revision numbers are, as ever, a handy shorthand that |
|
278 |
work in your local repository, but cannot be used across repositories. |
|
279 |
They also have the useful property of showing when there are hidden |
|
280 |
changesets lurking under the covers, which is why this document uses |
|
281 |
revision numbers. |
|
282 |
||
978 | 283 |
|
284 |
Under the hood: Prune an unwanted changeset |
|
285 |
=========================================== |
|
286 |
||
287 |
``prune`` (example 4 above) is the simplest history modification |
|
288 |
command provided by ``evolve``. All it does is mark the specified |
|
289 |
changeset(s) obsolete, with no successor/precursor relationships |
|
290 |
involved. (If the working directory parent was one of the obsolete |
|
291 |
changesets, ``prune`` updates back to a suitable ancestor.) |
|
292 |
||
293 |
.. figure:: figures/figure-ug03.svg |
|
294 |
||
295 |
Figure 3: pruning a changeset marks it obsolete with no successors. |
|
296 |
||
297 |
Under the hood: Uncommit changes to certain files |
|
298 |
================================================= |
|
299 |
||
300 |
In one sense, ``uncommit`` is a simplified version of ``amend``. Like |
|
301 |
``amend``, it obsoletes one changeset and leaves it with a single |
|
302 |
successor. Unlike ``amend``, there is no ugly "temporary amend commit" |
|
303 |
cluttering up the repository. |
|
304 |
||
305 |
In another sense, ``uncommit`` is the inverse of ``amend``: ``amend`` |
|
306 |
takes any uncommitted changes in the working dir and “adds” |
|
307 |
them to the working directory's parent changeset. (In reality, of |
|
308 |
course, it creates a successor changeset, marking the original |
|
309 |
obsolete.) In contrast, ``uncommit`` takes some changes in the working |
|
310 |
directory's parent and moves them to the working dir, creating a new |
|
311 |
successor changeset in the process. Figure 4 illustrates. |
|
312 |
||
313 |
.. figure:: figures/figure-ug04.svg |
|
314 |
||
315 |
Figure 4: uncommit moves some of the changes from the working |
|
316 |
directory parent into the working dir, preserving the remaining |
|
317 |
changes as a new successor changeset. (N.B. revision 4 is not shown |
|
318 |
here because it was marked obsolete in the previous example.) |
|
319 |
||
320 |
||
321 |
Under the hood: Fold multiple changesets together into one |
|
322 |
========================================================== |
|
323 |
||
324 |
The last basic example is folding multiple changesets into one, which |
|
325 |
marks multiple changesets obsolete, replacing them all with a single |
|
326 |
successor. |
|
327 |
||
328 |
.. figure:: figures/figure-ug05.svg |
|
329 |
||
330 |
Figure 5: fold combines multiple changesets into a single |
|
331 |
successor, marking the original (folded) changesets obsolete. |
|
332 |
||
333 |
||
334 |
Obsolete is not hidden |
|
335 |
====================== |
|
336 |
||
1269
250835154f8f
docs: explain that obsolete is not hidden
Greg Ward <greg@gerg.ca>
parents:
1268
diff
changeset
|
337 |
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
|
338 |
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
|
339 |
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
|
340 |
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
|
341 |
changesets. |
250835154f8f
docs: explain that obsolete is not hidden
Greg Ward <greg@gerg.ca>
parents:
1268
diff
changeset
|
342 |
|
250835154f8f
docs: explain that obsolete is not hidden
Greg Ward <greg@gerg.ca>
parents:
1268
diff
changeset
|
343 |
Note that all hidden changesets are obsolete: hidden is a subset of |
250835154f8f
docs: explain that obsolete is not hidden
Greg Ward <greg@gerg.ca>
parents:
1268
diff
changeset
|
344 |
obsolete. |
978 | 345 |
|
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 |
|
356 |
a consistent way for you to get out of trouble. |
|
357 |
||
358 |
(Incidentally, there are two other types of trouble that changesets |
|
359 |
can get into with ``evolve``: they may be *divergent* or *bumped*. |
|
360 |
Both of those states are more likely to occur when `sharing mutable |
|
361 |
history`_, so we won't see them in this user guide.) |
|
362 |
||
363 |
.. _`sharing mutable history`: sharing.html |
|
364 |
||
365 |
||
366 |
Example 7: Amend an older changeset |
|
367 |
=================================== |
|
368 |
||
369 |
Sometimes you don't notice your mistakes until after you have |
|
1267
8cc6e90354a9
docs: tweak wording, punctuation for better readability
Greg Ward <greg@gerg.ca>
parents:
978
diff
changeset
|
370 |
committed new changesets on top of them. :: |
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 |
||
405 |
All non-obsolete descendants of an obsolete changeset are unstable. An |
|
406 |
interesting consequence of this is that revision 11 is still visible, |
|
407 |
even though it is obsolete. Obsolete changesets with non-obsolete |
|
408 |
descendants are not hidden. |
|
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 |
|
418 |
to switch contexts from "writing code" to "resolving conflicts". That |
|
419 |
can be an expensive context switch, so Mercurial lets you decide when |
|
420 |
to do it. |
|
421 |
||
422 |
The end state, after ``evolve`` finishes, is that the original |
|
423 |
revisions (11-13) are obsolete and hidden. Their successor revisions |
|
424 |
(15-17) replace them. |
|
425 |
||
426 |
.. figure:: figures/figure-ug07.svg |
|
427 |
||
428 |
Figure 7: evolve your repository (``hg evolve --all``) to take care |
|
429 |
of instability. Unstable changesets become obsolete, and are |
|
430 |
replaced by successors just like the amended changeset was. |
|
431 |
||
432 |
Example 8: Prune an older changeset |
|
433 |
=================================== |
|
434 |
||
435 |
Let's say you've just committed the following changesets:: |
|
436 |
||
437 |
$ hg commit -m 'useful work' # rev 18 |
|
438 |
$ hg commit -m 'debug hack' # rev 19 |
|
439 |
$ hg commit -m 'more work' # rev 20 |
|
440 |
||
441 |
You want to drop revision 19, but keep 18 and 20. No problem:: |
|
442 |
||
443 |
$ hg prune 19 |
|
444 |
1 changesets pruned |
|
445 |
1 new unstable changesets |
|
446 |
||
447 |
As above, this leaves your repository in a funny intermediate state: |
|
448 |
revision 20 is the non-obsolete descendant of obsolete revision 19. |
|
449 |
That is, revision 20 is unstable. |
|
450 |
||
451 |
.. figure:: figures/figure-ug08.svg |
|
452 |
||
453 |
Figure 8: ``hg prune`` marks a changeset obsolete without creating |
|
454 |
a successor. Just like with ``hg amend``, non-obsolete descendants |
|
455 |
of the pruned changeset are now unstable. |
|
456 |
||
457 |
As before, the solution to unstable changesets is to evolve your |
|
458 |
repository:: |
|
459 |
||
460 |
$ hg evolve --all |
|
461 |
||
462 |
This rebases revision 20 on top of 18 as the new revision 21, leaving |
|
463 |
19 and 20 obsolete and hidden: |
|
464 |
||
465 |
.. figure:: figures/figure-ug09.svg |
|
466 |
||
467 |
Figure 9: once again, ``hg evolve --all`` takes care of instability. |
|
468 |
||
469 |
Example 9: Uncommit files from an older changeset (discard changes) |
|
470 |
======================================================================= |
|
471 |
||
472 |
As in example 5, let's say you accidentally commit some unrelated |
|
473 |
changes together. Unlike example 5, you don't notice your mistake |
|
474 |
immediately, but commit a new changeset on top of the bad one. :: |
|
475 |
||
476 |
$ echo 'this fixes bug 53' >> file1.c |
|
477 |
$ echo 'debug hack' >> file2.c |
|
478 |
$ hg commit -m 'fix bug 53' # rev 22 (oops) |
|
479 |
$ echo 'and this handles bug 67' >> file1.c |
|
480 |
$ hg commit -m 'fix bug 67' # rev 23 (fine) |
|
481 |
||
482 |
As with ``amend``, you need to travel back in time and repair revision |
|
483 |
22, leaving your changes to ``file2.c`` back in the working |
|
484 |
directory:: |
|
485 |
||
486 |
$ hg update 22 |
|
487 |
1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
488 |
$ hg uncommit file2.c |
|
489 |
1 new unstable changesets |
|
490 |
$ hg status |
|
491 |
M file2.c |
|
492 |
||
493 |
Now your repository has unstable changesets, so you need to evolve it. |
|
494 |
But ``hg evolve`` requires a clean working directory to resolve merge |
|
495 |
conflicts, so you need to decide what to do with ``file2.c``. |
|
496 |
||
497 |
In this case, the change to ``file2.c`` was a temporary debugging |
|
498 |
hack, so we can discard it and immediately evolve the instability away:: |
|
499 |
||
500 |
$ hg revert file2.c |
|
501 |
$ hg evolve --all |
|
502 |
move:[23] fix bug 67 |
|
503 |
atop:[24] fix bug 53 |
|
504 |
||
505 |
Figure 10 illustrates the whole process. |
|
506 |
||
507 |
.. figure:: figures/figure-ug10.svg |
|
508 |
||
509 |
Figure 10: ``hg uncommit`` of a changeset with descendants results |
|
510 |
in instability *and* a dirty working directory, both of which must |
|
511 |
be dealt with. |
|
512 |
||
513 |
||
514 |
Example 10: Uncommit files to an older changeset (keep changes) |
|
515 |
=================================================================== |
|
516 |
||
517 |
This is very similar to example 9. The difference that this time, our |
|
518 |
change to ``file2.c`` is valuable enough to commit, making things a |
|
519 |
bit more complicated. The setup is nearly identical:: |
|
520 |
||
521 |
$ echo 'fix a bug' >> file1.c |
|
522 |
$ echo 'useful but unrelated' >> file2.c |
|
523 |
$ hg commit -u dan -d '11 0' -m 'fix a bug' # rev 26 (oops) |
|
524 |
$ echo 'new feature' >> file1.c |
|
525 |
$ hg commit -u dan -d '12 0' -m 'new feature' # rev 27 (fine) |
|
526 |
||
527 |
As before, we update back to the flawed changeset (this time, |
|
528 |
revision 26) and ``uncommit``, leaving uncommitted changes to |
|
529 |
``file2.c`` in the working dir:: |
|
530 |
||
531 |
$ hg update -q 26 |
|
532 |
1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
533 |
$ hg uncommit -q file2.c # obsoletes rev 26, creates rev 28 |
|
534 |
1 new unstable changesets |
|
535 |
$ hg status |
|
536 |
M file2.c |
|
537 |
||
538 |
This time, let's save that useful change before evolving:: |
|
539 |
||
540 |
$ hg commit -m 'useful tweak' # rev 29 |
|
541 |
||
542 |
Figure 11 shows the story so far: ``uncommit`` obsoleted revision 26 |
|
543 |
and created revision 28, the successor of 26. Then we committed |
|
544 |
revision 29, a child of 28. We still have to deal with the unstable |
|
545 |
revision 27. |
|
546 |
||
547 |
.. figure:: figures/figure-ug11.svg |
|
548 |
||
549 |
Figure 11: Uncommitting a file and then committing that change |
|
550 |
separately will soon result in a two-headed repository. |
|
551 |
||
552 |
This is where things get tricky. As usual when a repository has |
|
553 |
unstable changesets, we want to evolve it:: |
|
554 |
||
555 |
$ hg evolve --all |
|
556 |
||
557 |
The problem is that ``hg evolve`` rebases revision 27 onto revision |
|
558 |
28, creating 30 (the successor of 27). This is entirely logical: 27 |
|
559 |
was the child of 26, and 26's successor is 28. So of course 27's |
|
560 |
successor (30) should be the child of 26's successor (28). |
|
561 |
Unfortunately, that leaves us with a two-headed repository: |
|
562 |
||
563 |
.. figure:: figures/figure-ug12.svg |
|
564 |
||
565 |
Figure 12: ``evolve`` takes care of unstable changesets; it does |
|
566 |
not solve all the world's problems. |
|
567 |
||
568 |
As usual when faced with a two-headed repository, you can either merge |
|
569 |
or rebase. It's up to you. |
|
570 |
||
571 |
||
572 |
Example 11: Recover an obsolete changeset |
|
573 |
========================================= |
|
574 |
||
1270 | 575 |
Sometimes you might obsolete a changeset, and then change your mind. You'll |
576 |
probably start looking for an “unobsolete” command to restore a changeset |
|
577 |
to normal state. For complicated implementation reasons, that command |
|
578 |
doesn't exist. (If you have already pushed an obsolescence marker to |
|
579 |
another repo, then Mercurial would need a way to revoke that remote |
|
580 |
obsolesence marker. That's a hard problem.) |
|
581 |
||
582 |
Instead, ``evolve`` provides a ``touch`` command to resurrect an |
|
583 |
obsolete changeset. An unexpected quirk: you almost certainly need to |
|
584 |
use ``--hidden``, since obsolete changesets tend to be hidden, and you |
|
585 |
can't reference a hidden changeset otherwise. Typical usage thus looks |
|
586 |
like :: |
|
587 |
||
588 |
$ hg --hidden touch REV |
|
589 |
||
590 |
This creates a new, normal changeset which is the same as ``REV``—except |
|
591 |
with a different changeset ID. The new changeset will have the same parent |
|
592 |
as ``REV``, and will be a successor of ``REV``. |
|
593 |
||
594 |
The current implementation of ``hg touch`` is not ideal, and is likely to |
|
595 |
change in the future. Consider the history in Figure 12, where revision 27 |
|
596 |
is obsolete and the child of 26, also obsolete. If we ``hg touch 27``, that |
|
597 |
creates a new revision which is a non-obsolete child of 26—i.e., it is |
|
598 |
unstable. It's also *divergent*, another type of trouble that we'll learn |
|
599 |
about in the `next section`_. |
|
600 |
||
601 |
.. _`next section`: sharing.html |