hgbook

view fr/ch09-undo.xml @ 983:5e1e70fcdfdb

Corrected some errors.
- Indentation problems
- Syntax errors (missing </para>,...)
- French mistakes
author Frédéric Bouquet <youshe.jaalon@gmail.com>
date Tue Sep 08 23:42:42 2009 +0200 (2009-09-08)
parents
children 6f8c48362758
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter>
4 <title>Finding and fixing your mistakes</title>
5 <para>\label{chap:undo}</para>
7 <para>To err might be human, but to really handle the consequences well
8 takes a top-notch revision control system. In this chapter, we'll
9 discuss some of the techniques you can use when you find that a
10 problem has crept into your project. Mercurial has some highly
11 capable features that will help you to isolate the sources of
12 problems, and to handle them appropriately.</para>
14 <sect1>
15 <title>Erasing local history</title>
17 <sect2>
18 <title>The accidental commit</title>
20 <para>I have the occasional but persistent problem of typing rather more
21 quickly than I can think, which sometimes results in me committing a
22 changeset that is either incomplete or plain wrong. In my case, the
23 usual kind of incomplete changeset is one in which I've created a new
24 source file, but forgotten to <command role="hg-cmd">hg add</command> it. A <quote>plain wrong</quote>
25 changeset is not as common, but no less annoying.</para>
27 </sect2>
28 <sect2>
29 <title>Rolling back a transaction</title>
30 <para>\label{sec:undo:rollback}</para>
32 <para>In section <xref linkend="sec:concepts:txn"/>, I mentioned that Mercurial treats
33 each modification of a repository as a <emphasis>transaction</emphasis>. Every time
34 you commit a changeset or pull changes from another repository,
35 Mercurial remembers what you did. You can undo, or <emphasis>roll back</emphasis>,
36 exactly one of these actions using the <command role="hg-cmd">hg rollback</command> command. (See
37 section <xref linkend="sec:undo:rollback-after-push"/> for an important caveat
38 about the use of this command.)</para>
40 <para>Here's a mistake that I often find myself making: committing a change
41 in which I've created a new file, but forgotten to <command role="hg-cmd">hg add</command> it.
42 <!-- &interaction.rollback.commit; -->
43 Looking at the output of <command role="hg-cmd">hg status</command> after the commit immediately
44 confirms the error.
45 <!-- &interaction.rollback.status; -->
46 The commit captured the changes to the file <filename>a</filename>, but not the
47 new file <filename>b</filename>. If I were to push this changeset to a
48 repository that I shared with a colleague, the chances are high that
49 something in <filename>a</filename> would refer to <filename>b</filename>, which would not
50 be present in their repository when they pulled my changes. I would
51 thus become the object of some indignation.</para>
53 <para>However, luck is with me&emdash;I've caught my error before I pushed the
54 changeset. I use the <command role="hg-cmd">hg rollback</command> command, and Mercurial makes
55 that last changeset vanish.
56 <!-- &interaction.rollback.rollback; -->
57 Notice that the changeset is no longer present in the repository's
58 history, and the working directory once again thinks that the file
59 <filename>a</filename> is modified. The commit and rollback have left the
60 working directory exactly as it was prior to the commit; the changeset
61 has been completely erased. I can now safely <command role="hg-cmd">hg add</command> the file
62 <filename>b</filename>, and rerun my commit.
63 <!-- &interaction.rollback.add; --></para>
65 </sect2>
66 <sect2>
67 <title>The erroneous pull</title>
69 <para>It's common practice with Mercurial to maintain separate development
70 branches of a project in different repositories. Your development
71 team might have one shared repository for your project's <quote>0.9</quote>
72 release, and another, containing different changes, for the <quote>1.0</quote>
73 release.</para>
75 <para>Given this, you can imagine that the consequences could be messy if
76 you had a local <quote>0.9</quote> repository, and accidentally pulled changes
77 from the shared <quote>1.0</quote> repository into it. At worst, you could be
78 paying insufficient attention, and push those changes into the shared
79 <quote>0.9</quote> tree, confusing your entire team (but don't worry, we'll
80 return to this horror scenario later). However, it's more likely that
81 you'll notice immediately, because Mercurial will display the URL it's
82 pulling from, or you will see it pull a suspiciously large number of
83 changes into the repository.
84 </para>
86 <para>The <command role="hg-cmd">hg rollback</command> command will work nicely to expunge all of the
87 changesets that you just pulled. Mercurial groups all changes from
88 one <command role="hg-cmd">hg pull</command> into a single transaction, so one <command role="hg-cmd">hg rollback</command> is
89 all you need to undo this mistake.
90 </para>
92 </sect2>
93 <sect2>
94 <title>Rolling back is useless once you've pushed</title>
95 <para>\label{sec:undo:rollback-after-push}
96 </para>
98 <para>The value of the <command role="hg-cmd">hg rollback</command> command drops to zero once you've
99 pushed your changes to another repository. Rolling back a change
100 makes it disappear entirely, but <emphasis>only</emphasis> in the repository in
101 which you perform the <command role="hg-cmd">hg rollback</command>. Because a rollback eliminates
102 history, there's no way for the disappearance of a change to propagate
103 between repositories.
104 </para>
106 <para>If you've pushed a change to another repository&emdash;particularly if it's
107 a shared repository&emdash;it has essentially <quote>escaped into the wild,</quote>
108 and you'll have to recover from your mistake in a different way. What
109 will happen if you push a changeset somewhere, then roll it back, then
110 pull from the repository you pushed to, is that the changeset will
111 reappear in your repository.
112 </para>
114 <para>(If you absolutely know for sure that the change you want to roll back
115 is the most recent change in the repository that you pushed to,
116 <emphasis>and</emphasis> you know that nobody else could have pulled it from that
117 repository, you can roll back the changeset there, too, but you really
118 should really not rely on this working reliably. If you do this,
119 sooner or later a change really will make it into a repository that
120 you don't directly control (or have forgotten about), and come back to
121 bite you.)
122 </para>
124 </sect2>
125 <sect2>
126 <title>You can only roll back once</title>
128 <para>Mercurial stores exactly one transaction in its transaction log; that
129 transaction is the most recent one that occurred in the repository.
130 This means that you can only roll back one transaction. If you expect
131 to be able to roll back one transaction, then its predecessor, this is
132 not the behaviour you will get.
133 <!-- &interaction.rollback.twice; -->
134 Once you've rolled back one transaction in a repository, you can't
135 roll back again in that repository until you perform another commit or
136 pull.
137 </para>
139 </sect2>
140 </sect1>
141 <sect1>
142 <title>Reverting the mistaken change</title>
144 <para>If you make a modification to a file, and decide that you really
145 didn't want to change the file at all, and you haven't yet committed
146 your changes, the <command role="hg-cmd">hg revert</command> command is the one you'll need. It
147 looks at the changeset that's the parent of the working directory, and
148 restores the contents of the file to their state as of that changeset.
149 (That's a long-winded way of saying that, in the normal case, it
150 undoes your modifications.)
151 </para>
153 <para>Let's illustrate how the <command role="hg-cmd">hg revert</command> command works with yet another
154 small example. We'll begin by modifying a file that Mercurial is
155 already tracking.
156 <!-- &interaction.daily.revert.modify; -->
157 If we don't want that change, we can simply <command role="hg-cmd">hg revert</command> the file.
158 <!-- &interaction.daily.revert.unmodify; -->
159 The <command role="hg-cmd">hg revert</command> command provides us with an extra degree of safety
160 by saving our modified file with a <filename>.orig</filename> extension.
161 <!-- &interaction.daily.revert.status; -->
162 </para>
164 <para>Here is a summary of the cases that the <command role="hg-cmd">hg revert</command> command can
165 deal with. We will describe each of these in more detail in the
166 section that follows.
167 </para>
168 <itemizedlist>
169 <listitem><para>If you modify a file, it will restore the file to its unmodified
170 state.
171 </para>
172 </listitem>
173 <listitem><para>If you <command role="hg-cmd">hg add</command> a file, it will undo the <quote>added</quote> state of
174 the file, but leave the file itself untouched.
175 </para>
176 </listitem>
177 <listitem><para>If you delete a file without telling Mercurial, it will restore
178 the file to its unmodified contents.
179 </para>
180 </listitem>
181 <listitem><para>If you use the <command role="hg-cmd">hg remove</command> command to remove a file, it will
182 undo the <quote>removed</quote> state of the file, and restore the file to its
183 unmodified contents.
184 </para>
185 </listitem></itemizedlist>
187 <sect2>
188 <title>File management errors</title>
189 <para>\label{sec:undo:mgmt}
190 </para>
192 <para>The <command role="hg-cmd">hg revert</command> command is useful for more than just modified
193 files. It lets you reverse the results of all of Mercurial's file
194 management commands&emdash;<command role="hg-cmd">hg add</command>, <command role="hg-cmd">hg remove</command>, and so on.
195 </para>
197 <para>If you <command role="hg-cmd">hg add</command> a file, then decide that in fact you don't want
198 Mercurial to track it, use <command role="hg-cmd">hg revert</command> to undo the add. Don't
199 worry; Mercurial will not modify the file in any way. It will just
200 <quote>unmark</quote> the file.
201 <!-- &interaction.daily.revert.add; -->
202 </para>
204 <para>Similarly, if you ask Mercurial to <command role="hg-cmd">hg remove</command> a file, you can use
205 <command role="hg-cmd">hg revert</command> to restore it to the contents it had as of the parent
206 of the working directory.
207 <!-- &interaction.daily.revert.remove; -->
208 This works just as well for a file that you deleted by hand, without
209 telling Mercurial (recall that in Mercurial terminology, this kind of
210 file is called <quote>missing</quote>).
211 <!-- &interaction.daily.revert.missing; -->
212 </para>
214 <para>If you revert a <command role="hg-cmd">hg copy</command>, the copied-to file remains in your
215 working directory afterwards, untracked. Since a copy doesn't affect
216 the copied-from file in any way, Mercurial doesn't do anything with
217 the copied-from file.
218 <!-- &interaction.daily.revert.copy; -->
219 </para>
221 <sect3>
222 <title>A slightly special case: reverting a rename</title>
224 <para>If you <command role="hg-cmd">hg rename</command> a file, there is one small detail that
225 you should remember. When you <command role="hg-cmd">hg revert</command> a rename, it's not
226 enough to provide the name of the renamed-to file, as you can see
227 here.
228 <!-- &interaction.daily.revert.rename; -->
229 As you can see from the output of <command role="hg-cmd">hg status</command>, the renamed-to file
230 is no longer identified as added, but the renamed-<emphasis>from</emphasis> file is
231 still removed! This is counter-intuitive (at least to me), but at
232 least it's easy to deal with.
233 <!-- &interaction.daily.revert.rename-orig; -->
234 So remember, to revert a <command role="hg-cmd">hg rename</command>, you must provide <emphasis>both</emphasis>
235 the source and destination names.
236 </para>
238 <para>% TODO: the output doesn't look like it will be removed!
239 </para>
241 <para>(By the way, if you rename a file, then modify the renamed-to file,
242 then revert both components of the rename, when Mercurial restores the
243 file that was removed as part of the rename, it will be unmodified.
244 If you need the modifications in the renamed-to file to show up in the
245 renamed-from file, don't forget to copy them over.)
246 </para>
248 <para>These fiddly aspects of reverting a rename arguably constitute a small
249 bug in Mercurial.
250 </para>
252 </sect3>
253 </sect2>
254 </sect1>
255 <sect1>
256 <title>Dealing with committed changes</title>
258 <para>Consider a case where you have committed a change $a$, and another
259 change $b$ on top of it; you then realise that change $a$ was
260 incorrect. Mercurial lets you <quote>back out</quote> an entire changeset
261 automatically, and building blocks that let you reverse part of a
262 changeset by hand.
263 </para>
265 <para>Before you read this section, here's something to keep in mind: the
266 <command role="hg-cmd">hg backout</command> command undoes changes by <emphasis>adding</emphasis> history, not
267 by modifying or erasing it. It's the right tool to use if you're
268 fixing bugs, but not if you're trying to undo some change that has
269 catastrophic consequences. To deal with those, see
270 section <xref linkend="sec:undo:aaaiiieee"/>.
271 </para>
273 <sect2>
274 <title>Backing out a changeset</title>
276 <para>The <command role="hg-cmd">hg backout</command> command lets you <quote>undo</quote> the effects of an entire
277 changeset in an automated fashion. Because Mercurial's history is
278 immutable, this command <emphasis>does not</emphasis> get rid of the changeset you
279 want to undo. Instead, it creates a new changeset that
280 <emphasis>reverses</emphasis> the effect of the to-be-undone changeset.
281 </para>
283 <para>The operation of the <command role="hg-cmd">hg backout</command> command is a little intricate, so
284 let's illustrate it with some examples. First, we'll create a
285 repository with some simple changes.
286 <!-- &interaction.backout.init; -->
287 </para>
289 <para>The <command role="hg-cmd">hg backout</command> command takes a single changeset ID as its
290 argument; this is the changeset to back out. Normally,
291 <command role="hg-cmd">hg backout</command> will drop you into a text editor to write a commit
292 message, so you can record why you're backing the change out. In this
293 example, we provide a commit message on the command line using the
294 <option role="hg-opt-backout">-m</option> option.
295 </para>
297 </sect2>
298 <sect2>
299 <title>Backing out the tip changeset</title>
301 <para>We're going to start by backing out the last changeset we committed.
302 <!-- &interaction.backout.simple; -->
303 You can see that the second line from <filename>myfile</filename> is no longer
304 present. Taking a look at the output of <command role="hg-cmd">hg log</command> gives us an idea
305 of what the <command role="hg-cmd">hg backout</command> command has done.
306 <!-- &interaction.backout.simple.log; -->
307 Notice that the new changeset that <command role="hg-cmd">hg backout</command> has created is a
308 child of the changeset we backed out. It's easier to see this in
309 figure <xref linkend="fig:undo:backout"/>, which presents a graphical view of the
310 change history. As you can see, the history is nice and linear.
311 </para>
313 <informalfigure>
315 <para> <mediaobject><imageobject><imagedata fileref="undo-simple"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
316 <caption><para>Backing out a change using the <command role="hg-cmd">hg backout</command> command</para></caption>
317 \label{fig:undo:backout}
318 </para>
319 </informalfigure>
321 </sect2>
322 <sect2>
323 <title>Backing out a non-tip change</title>
325 <para>If you want to back out a change other than the last one you
326 committed, pass the <option role="hg-opt-backout">--merge</option> option to the
327 <command role="hg-cmd">hg backout</command> command.
328 <!-- &interaction.backout.non-tip.clone; -->
329 This makes backing out any changeset a <quote>one-shot</quote> operation that's
330 usually simple and fast.
331 <!-- &interaction.backout.non-tip.backout; -->
332 </para>
334 <para>If you take a look at the contents of <filename>myfile</filename> after the
335 backout finishes, you'll see that the first and third changes are
336 present, but not the second.
337 <!-- &interaction.backout.non-tip.cat; -->
338 </para>
340 <para>As the graphical history in figure <xref linkend="fig:undo:backout-non-tip"/>
341 illustrates, Mercurial actually commits <emphasis>two</emphasis> changes in this
342 kind of situation (the box-shaped nodes are the ones that Mercurial
343 commits automatically). Before Mercurial begins the backout process,
344 it first remembers what the current parent of the working directory
345 is. It then backs out the target changeset, and commits that as a
346 changeset. Finally, it merges back to the previous parent of the
347 working directory, and commits the result of the merge.
348 </para>
350 <para>% TODO: to me it looks like mercurial doesn't commit the second merge automatically!
351 </para>
353 <informalfigure>
355 <para> <mediaobject><imageobject><imagedata fileref="undo-non-tip"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
356 <caption><para>Automated backout of a non-tip change using the <command role="hg-cmd">hg backout</command> command</para></caption>
357 \label{fig:undo:backout-non-tip}
358 </para>
359 </informalfigure>
361 <para>The result is that you end up <quote>back where you were</quote>, only with some
362 extra history that undoes the effect of the changeset you wanted to
363 back out.
364 </para>
366 <sect3>
367 <title>Always use the <option role="hg-opt-backout">--merge</option> option</title>
369 <para>In fact, since the <option role="hg-opt-backout">--merge</option> option will do the <quote>right
370 thing</quote> whether or not the changeset you're backing out is the tip
371 (i.e. it won't try to merge if it's backing out the tip, since there's
372 no need), you should <emphasis>always</emphasis> use this option when you run the
373 <command role="hg-cmd">hg backout</command> command.
374 </para>
376 </sect3>
377 </sect2>
378 <sect2>
379 <title>Gaining more control of the backout process</title>
381 <para>While I've recommended that you always use the
382 <option role="hg-opt-backout">--merge</option> option when backing out a change, the
383 <command role="hg-cmd">hg backout</command> command lets you decide how to merge a backout
384 changeset. Taking control of the backout process by hand is something
385 you will rarely need to do, but it can be useful to understand what
386 the <command role="hg-cmd">hg backout</command> command is doing for you automatically. To
387 illustrate this, let's clone our first repository, but omit the
388 backout change that it contains.
389 </para>
391 <para><!-- &interaction.backout.manual.clone; -->
392 As with our earlier example, We'll commit a third changeset, then back
393 out its parent, and see what happens.
394 <!-- &interaction.backout.manual.backout; -->
395 Our new changeset is again a descendant of the changeset we backout
396 out; it's thus a new head, <emphasis>not</emphasis> a descendant of the changeset
397 that was the tip. The <command role="hg-cmd">hg backout</command> command was quite explicit in
398 telling us this.
399 <!-- &interaction.backout.manual.log; -->
400 </para>
402 <para>Again, it's easier to see what has happened by looking at a graph of
403 the revision history, in figure <xref linkend="fig:undo:backout-manual"/>. This
404 makes it clear that when we use <command role="hg-cmd">hg backout</command> to back out a change
405 other than the tip, Mercurial adds a new head to the repository (the
406 change it committed is box-shaped).
407 </para>
409 <informalfigure>
411 <para> <mediaobject><imageobject><imagedata fileref="undo-manual"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
412 <caption><para>Backing out a change using the <command role="hg-cmd">hg backout</command> command</para></caption>
413 \label{fig:undo:backout-manual}
414 </para>
415 </informalfigure>
417 <para>After the <command role="hg-cmd">hg backout</command> command has completed, it leaves the new
418 <quote>backout</quote> changeset as the parent of the working directory.
419 <!-- &interaction.backout.manual.parents; -->
420 Now we have two isolated sets of changes.
421 <!-- &interaction.backout.manual.heads; -->
422 </para>
424 <para>Let's think about what we expect to see as the contents of
425 <filename>myfile</filename> now. The first change should be present, because
426 we've never backed it out. The second change should be missing, as
427 that's the change we backed out. Since the history graph shows the
428 third change as a separate head, we <emphasis>don't</emphasis> expect to see the
429 third change present in <filename>myfile</filename>.
430 <!-- &interaction.backout.manual.cat; -->
431 To get the third change back into the file, we just do a normal merge
432 of our two heads.
433 <!-- &interaction.backout.manual.merge; -->
434 Afterwards, the graphical history of our repository looks like
435 figure <xref linkend="fig:undo:backout-manual-merge"/>.
436 </para>
438 <informalfigure>
440 <para> <mediaobject><imageobject><imagedata fileref="undo-manual-merge"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
441 <caption><para>Manually merging a backout change</para></caption>
442 \label{fig:undo:backout-manual-merge}
443 </para>
444 </informalfigure>
446 </sect2>
447 <sect2>
448 <title>Why <command role="hg-cmd">hg backout</command> works as it does</title>
450 <para>Here's a brief description of how the <command role="hg-cmd">hg backout</command> command works.
451 </para>
452 <orderedlist>
453 <listitem><para>It ensures that the working directory is <quote>clean</quote>, i.e. that
454 the output of <command role="hg-cmd">hg status</command> would be empty.
455 </para>
456 </listitem>
457 <listitem><para>It remembers the current parent of the working directory. Let's
458 call this changeset <literal>orig</literal>
459 </para>
460 </listitem>
461 <listitem><para>It does the equivalent of a <command role="hg-cmd">hg update</command> to sync the working
462 directory to the changeset you want to back out. Let's call this
463 changeset <literal>backout</literal>
464 </para>
465 </listitem>
466 <listitem><para>It finds the parent of that changeset. Let's call that
467 changeset <literal>parent</literal>.
468 </para>
469 </listitem>
470 <listitem><para>For each file that the <literal>backout</literal> changeset affected, it
471 does the equivalent of a <command role="hg-cmd">hg revert -r parent</command> on that file,
472 to restore it to the contents it had before that changeset was
473 committed.
474 </para>
475 </listitem>
476 <listitem><para>It commits the result as a new changeset. This changeset has
477 <literal>backout</literal> as its parent.
478 </para>
479 </listitem>
480 <listitem><para>If you specify <option role="hg-opt-backout">--merge</option> on the command line, it
481 merges with <literal>orig</literal>, and commits the result of the merge.
482 </para>
483 </listitem></orderedlist>
485 <para>An alternative way to implement the <command role="hg-cmd">hg backout</command> command would be
486 to <command role="hg-cmd">hg export</command> the to-be-backed-out changeset as a diff, then use
487 the <option role="cmd-opt-patch">--reverse</option> option to the <command>patch</command> command to
488 reverse the effect of the change without fiddling with the working
489 directory. This sounds much simpler, but it would not work nearly as
490 well.
491 </para>
493 <para>The reason that <command role="hg-cmd">hg backout</command> does an update, a commit, a merge, and
494 another commit is to give the merge machinery the best chance to do a
495 good job when dealing with all the changes <emphasis>between</emphasis> the change
496 you're backing out and the current tip.
497 </para>
499 <para>If you're backing out a changeset that's 100 revisions back in your
500 project's history, the chances that the <command>patch</command> command will
501 be able to apply a reverse diff cleanly are not good, because
502 intervening changes are likely to have <quote>broken the context</quote> that
503 <command>patch</command> uses to determine whether it can apply a patch (if
504 this sounds like gibberish, see <xref linkend="sec:mq:patch"/> for a
505 discussion of the <command>patch</command> command). Also, Mercurial's merge
506 machinery will handle files and directories being renamed, permission
507 changes, and modifications to binary files, none of which
508 <command>patch</command> can deal with.
509 </para>
511 </sect2>
512 </sect1>
513 <sect1>
514 <title>Changes that should never have been</title>
515 <para>\label{sec:undo:aaaiiieee}
516 </para>
518 <para>Most of the time, the <command role="hg-cmd">hg backout</command> command is exactly what you need
519 if you want to undo the effects of a change. It leaves a permanent
520 record of exactly what you did, both when committing the original
521 changeset and when you cleaned up after it.
522 </para>
524 <para>On rare occasions, though, you may find that you've committed a change
525 that really should not be present in the repository at all. For
526 example, it would be very unusual, and usually considered a mistake,
527 to commit a software project's object files as well as its source
528 files. Object files have almost no intrinsic value, and they're
529 <emphasis>big</emphasis>, so they increase the size of the repository and the amount
530 of time it takes to clone or pull changes.
531 </para>
533 <para>Before I discuss the options that you have if you commit a <quote>brown
534 paper bag</quote> change (the kind that's so bad that you want to pull a
535 brown paper bag over your head), let me first discuss some approaches
536 that probably won't work.
537 </para>
539 <para>Since Mercurial treats history as accumulative&emdash;every change builds
540 on top of all changes that preceded it&emdash;you generally can't just make
541 disastrous changes disappear. The one exception is when you've just
542 committed a change, and it hasn't been pushed or pulled into another
543 repository. That's when you can safely use the <command role="hg-cmd">hg rollback</command>
544 command, as I detailed in section <xref linkend="sec:undo:rollback"/>.
545 </para>
547 <para>After you've pushed a bad change to another repository, you
548 <emphasis>could</emphasis> still use <command role="hg-cmd">hg rollback</command> to make your local copy of the
549 change disappear, but it won't have the consequences you want. The
550 change will still be present in the remote repository, so it will
551 reappear in your local repository the next time you pull.
552 </para>
554 <para>If a situation like this arises, and you know which repositories your
555 bad change has propagated into, you can <emphasis>try</emphasis> to get rid of the
556 changeefrom <emphasis>every</emphasis> one of those repositories. This is, of
557 course, not a satisfactory solution: if you miss even a single
558 repository while you're expunging, the change is still <quote>in the
559 wild</quote>, and could propagate further.
560 </para>
562 <para>If you've committed one or more changes <emphasis>after</emphasis> the change that
563 you'd like to see disappear, your options are further reduced.
564 Mercurial doesn't provide a way to <quote>punch a hole</quote> in history,
565 leaving changesets intact.
566 </para>
568 <para>XXX This needs filling out. The <literal>hg-replay</literal> script in the
569 <literal>examples</literal> directory works, but doesn't handle merge
570 changesets. Kind of an important omission.
571 </para>
573 <sect2>
574 <title>Protect yourself from <quote>escaped</quote> changes</title>
576 <para>If you've committed some changes to your local repository and they've
577 been pushed or pulled somewhere else, this isn't necessarily a
578 disaster. You can protect yourself ahead of time against some classes
579 of bad changeset. This is particularly easy if your team usually
580 pulls changes from a central repository.
581 </para>
583 <para>By configuring some hooks on that repository to validate incoming
584 changesets (see chapter <xref linkend="chap:hook"/>), you can automatically
585 prevent some kinds of bad changeset from being pushed to the central
586 repository at all. With such a configuration in place, some kinds of
587 bad changeset will naturally tend to <quote>die out</quote> because they can't
588 propagate into the central repository. Better yet, this happens
589 without any need for explicit intervention.
590 </para>
592 <para>For instance, an incoming change hook that verifies that a changeset
593 will actually compile can prevent people from inadvertantly <quote>breaking
594 the build</quote>.
595 </para>
597 </sect2>
598 </sect1>
599 <sect1>
600 <title>Finding the source of a bug</title>
601 <para>\label{sec:undo:bisect}
602 </para>
604 <para>While it's all very well to be able to back out a changeset that
605 introduced a bug, this requires that you know which changeset to back
606 out. Mercurial provides an invaluable command, called
607 <command role="hg-cmd">hg bisect</command>, that helps you to automate this process and accomplish
608 it very efficiently.
609 </para>
611 <para>The idea behind the <command role="hg-cmd">hg bisect</command> command is that a changeset has
612 introduced some change of behaviour that you can identify with a
613 simple binary test. You don't know which piece of code introduced the
614 change, but you know how to test for the presence of the bug. The
615 <command role="hg-cmd">hg bisect</command> command uses your test to direct its search for the
616 changeset that introduced the code that caused the bug.
617 </para>
619 <para>Here are a few scenarios to help you understand how you might apply
620 this command.
621 </para>
622 <itemizedlist>
623 <listitem><para>The most recent version of your software has a bug that you
624 remember wasn't present a few weeks ago, but you don't know when it
625 was introduced. Here, your binary test checks for the presence of
626 that bug.
627 </para>
628 </listitem>
629 <listitem><para>You fixed a bug in a rush, and now it's time to close the entry
630 in your team's bug database. The bug database requires a changeset
631 ID when you close an entry, but you don't remember which changeset
632 you fixed the bug in. Once again, your binary test checks for the
633 presence of the bug.
634 </para>
635 </listitem>
636 <listitem><para>Your software works correctly, but runs 15% slower than the
637 last time you measured it. You want to know which changeset
638 introduced the performance regression. In this case, your binary
639 test measures the performance of your software, to see whether it's
640 <quote>fast</quote> or <quote>slow</quote>.
641 </para>
642 </listitem>
643 <listitem><para>The sizes of the components of your project that you ship
644 exploded recently, and you suspect that something changed in the way
645 you build your project.
646 </para>
647 </listitem></itemizedlist>
649 <para>From these examples, it should be clear that the <command role="hg-cmd">hg bisect</command>
650 command is not useful only for finding the sources of bugs. You can
651 use it to find any <quote>emergent property</quote> of a repository (anything
652 that you can't find from a simple text search of the files in the
653 tree) for which you can write a binary test.
654 </para>
656 <para>We'll introduce a little bit of terminology here, just to make it
657 clear which parts of the search process are your responsibility, and
658 which are Mercurial's. A <emphasis>test</emphasis> is something that <emphasis>you</emphasis> run
659 when <command role="hg-cmd">hg bisect</command> chooses a changeset. A <emphasis>probe</emphasis> is what
660 <command role="hg-cmd">hg bisect</command> runs to tell whether a revision is good. Finally,
661 we'll use the word <quote>bisect</quote>, as both a noun and a verb, to stand in
662 for the phrase <quote>search using the <command role="hg-cmd">hg bisect</command> command.
663 </para>
665 <para>One simple way to automate the searching process would be simply to
666 probe every changeset. However, this scales poorly. If it took ten
667 minutes to test a single changeset, and you had 10,000 changesets in
668 your repository, the exhaustive approach would take on average 35
669 <emphasis>days</emphasis> to find the changeset that introduced a bug. Even if you
670 knew that the bug was introduced by one of the last 500 changesets,
671 and limited your search to those, you'd still be looking at over 40
672 hours to find the changeset that introduced your bug.
673 </para>
675 <para>What the <command role="hg-cmd">hg bisect</command> command does is use its knowledge of the
676 <quote>shape</quote> of your project's revision history to perform a search in
677 time proportional to the <emphasis>logarithm</emphasis> of the number of changesets
678 to check (the kind of search it performs is called a dichotomic
679 search). With this approach, searching through 10,000 changesets will
680 take less than three hours, even at ten minutes per test (the search
681 will require about 14 tests). Limit your search to the last hundred
682 changesets, and it will take only about an hour (roughly seven tests).
683 </para>
685 <para>The <command role="hg-cmd">hg bisect</command> command is aware of the <quote>branchy</quote> nature of a
686 Mercurial project's revision history, so it has no problems dealing
687 with branches, merges, or multiple heads in a repository. It can
688 prune entire branches of history with a single probe, which is how it
689 operates so efficiently.
690 </para>
692 <sect2>
693 <title>Using the <command role="hg-cmd">hg bisect</command> command</title>
695 <para>Here's an example of <command role="hg-cmd">hg bisect</command> in action.
696 </para>
698 <note>
699 <para> In versions 0.9.5 and earlier of Mercurial, <command role="hg-cmd">hg bisect</command> was not a
700 core command: it was distributed with Mercurial as an extension.
701 This section describes the built-in command, not the old extension.
702 </para>
703 </note>
705 <para>Now let's create a repository, so that we can try out the
706 <command role="hg-cmd">hg bisect</command> command in isolation.
707 <!-- &interaction.bisect.init; -->
708 We'll simulate a project that has a bug in it in a simple-minded way:
709 create trivial changes in a loop, and nominate one specific change
710 that will have the <quote>bug</quote>. This loop creates 35 changesets, each
711 adding a single file to the repository. We'll represent our <quote>bug</quote>
712 with a file that contains the text <quote>i have a gub</quote>.
713 <!-- &interaction.bisect.commits; -->
714 </para>
716 <para>The next thing that we'd like to do is figure out how to use the
717 <command role="hg-cmd">hg bisect</command> command. We can use Mercurial's normal built-in help
718 mechanism for this.
719 <!-- &interaction.bisect.help; -->
720 </para>
722 <para>The <command role="hg-cmd">hg bisect</command> command works in steps. Each step proceeds as follows.
723 </para>
724 <orderedlist>
725 <listitem><para>You run your binary test.
726 </para>
727 </listitem><itemizedlist>
728 <listitem><para> \item If the test succeeded, you tell <command role="hg-cmd">hg bisect</command> by running the
729 <command role="hg-cmd">hg bisect good</command> command.
730 \item If it failed, run the <command role="hg-cmd">hg bisect --bad</command> command.
731 </para>
732 </listitem></itemizedlist>
733 <listitem><para>The command uses your information to decide which changeset to
734 test next.
735 </para>
736 </listitem>
737 <listitem><para>It updates the working directory to that changeset, and the
738 process begins again.
739 </para>
740 </listitem></orderedlist>
741 <para>The process ends when <command role="hg-cmd">hg bisect</command> identifies a unique changeset
742 that marks the point where your test transitioned from <quote>succeeding</quote>
743 to <quote>failing</quote>.
744 </para>
746 <para>To start the search, we must run the <command role="hg-cmd">hg bisect --reset</command> command.
747 <!-- &interaction.bisect.search.init; -->
748 </para>
750 <para>In our case, the binary test we use is simple: we check to see if any
751 file in the repository contains the string <quote>i have a gub</quote>. If it
752 does, this changeset contains the change that <quote>caused the bug</quote>. By
753 convention, a changeset that has the property we're searching for is
754 <quote>bad</quote>, while one that doesn't is <quote>good</quote>.
755 </para>
757 <para>Most of the time, the revision to which the working directory is
758 synced (usually the tip) already exhibits the problem introduced by
759 the buggy change, so we'll mark it as <quote>bad</quote>.
760 <!-- &interaction.bisect.search.bad-init; -->
761 </para>
763 <para>Our next task is to nominate a changeset that we know <emphasis>doesn't</emphasis>
764 have the bug; the <command role="hg-cmd">hg bisect</command> command will <quote>bracket</quote> its search
765 between the first pair of good and bad changesets. In our case, we
766 know that revision 10 didn't have the bug. (I'll have more words
767 about choosing the first <quote>good</quote> changeset later.)
768 <!-- &interaction.bisect.search.good-init; -->
769 </para>
771 <para>Notice that this command printed some output.
772 </para>
773 <itemizedlist>
774 <listitem><para>It told us how many changesets it must consider before it can
775 identify the one that introduced the bug, and how many tests that
776 will require.
777 </para>
778 </listitem>
779 <listitem><para>It updated the working directory to the next changeset to test,
780 and told us which changeset it's testing.
781 </para>
782 </listitem></itemizedlist>
784 <para>We now run our test in the working directory. We use the
785 <command>grep</command> command to see if our <quote>bad</quote> file is present in the
786 working directory. If it is, this revision is bad; if not, this
787 revision is good.
788 <!-- &interaction.bisect.search.step1; -->
789 </para>
791 <para>This test looks like a perfect candidate for automation, so let's turn
792 it into a shell function.
793 <!-- &interaction.bisect.search.mytest; -->
794 We can now run an entire test step with a single command,
795 <literal>mytest</literal>.
796 <!-- &interaction.bisect.search.step2; -->
797 A few more invocations of our canned test step command, and we're
798 done.
799 <!-- &interaction.bisect.search.rest; -->
800 </para>
802 <para>Even though we had 40 changesets to search through, the <command role="hg-cmd">hg bisect</command>
803 command let us find the changeset that introduced our <quote>bug</quote> with
804 only five tests. Because the number of tests that the <command role="hg-cmd">hg bisect</command>
805 command performs grows logarithmically with the number of changesets to
806 search, the advantage that it has over the <quote>brute force</quote> search
807 approach increases with every changeset you add.
808 </para>
810 </sect2>
811 <sect2>
812 <title>Cleaning up after your search</title>
814 <para>When you're finished using the <command role="hg-cmd">hg bisect</command> command in a
815 repository, you can use the <command role="hg-cmd">hg bisect reset</command> command to drop
816 the information it was using to drive your search. The command
817 doesn't use much space, so it doesn't matter if you forget to run this
818 command. However, <command role="hg-cmd">hg bisect</command> won't let you start a new search in
819 that repository until you do a <command role="hg-cmd">hg bisect reset</command>.
820 <!-- &interaction.bisect.search.reset; -->
821 </para>
823 </sect2>
824 </sect1>
825 <sect1>
826 <title>Tips for finding bugs effectively</title>
828 <sect2>
829 <title>Give consistent input</title>
831 <para>The <command role="hg-cmd">hg bisect</command> command requires that you correctly report the
832 result of every test you perform. If you tell it that a test failed
833 when it really succeeded, it <emphasis>might</emphasis> be able to detect the
834 inconsistency. If it can identify an inconsistency in your reports,
835 it will tell you that a particular changeset is both good and bad.
836 However, it can't do this perfectly; it's about as likely to report
837 the wrong changeset as the source of the bug.
838 </para>
840 </sect2>
841 <sect2>
842 <title>Automate as much as possible</title>
844 <para>When I started using the <command role="hg-cmd">hg bisect</command> command, I tried a few times
845 to run my tests by hand, on the command line. This is an approach
846 that I, at least, am not suited to. After a few tries, I found that I
847 was making enough mistakes that I was having to restart my searches
848 several times before finally getting correct results.
849 </para>
851 <para>My initial problems with driving the <command role="hg-cmd">hg bisect</command> command by hand
852 occurred even with simple searches on small repositories; if the
853 problem you're looking for is more subtle, or the number of tests that
854 <command role="hg-cmd">hg bisect</command> must perform increases, the likelihood of operator
855 error ruining the search is much higher. Once I started automating my
856 tests, I had much better results.
857 </para>
859 <para>The key to automated testing is twofold:
860 </para>
861 <itemizedlist>
862 <listitem><para>always test for the same symptom, and
863 </para>
864 </listitem>
865 <listitem><para>always feed consistent input to the <command role="hg-cmd">hg bisect</command> command.
866 </para>
867 </listitem></itemizedlist>
868 <para>In my tutorial example above, the <command>grep</command> command tests for the
869 symptom, and the <literal>if</literal> statement takes the result of this check
870 and ensures that we always feed the same input to the <command role="hg-cmd">hg bisect</command>
871 command. The <literal>mytest</literal> function marries these together in a
872 reproducible way, so that every test is uniform and consistent.
873 </para>
875 </sect2>
876 <sect2>
877 <title>Check your results</title>
879 <para>Because the output of a <command role="hg-cmd">hg bisect</command> search is only as good as the
880 input you give it, don't take the changeset it reports as the
881 absolute truth. A simple way to cross-check its report is to manually
882 run your test at each of the following changesets:
883 </para>
884 <itemizedlist>
885 <listitem><para>The changeset that it reports as the first bad revision. Your
886 test should still report this as bad.
887 </para>
888 </listitem>
889 <listitem><para>The parent of that changeset (either parent, if it's a merge).
890 Your test should report this changeset as good.
891 </para>
892 </listitem>
893 <listitem><para>A child of that changeset. Your test should report this
894 changeset as bad.
895 </para>
896 </listitem></itemizedlist>
898 </sect2>
899 <sect2>
900 <title>Beware interference between bugs</title>
902 <para>It's possible that your search for one bug could be disrupted by the
903 presence of another. For example, let's say your software crashes at
904 revision 100, and worked correctly at revision 50. Unknown to you,
905 someone else introduced a different crashing bug at revision 60, and
906 fixed it at revision 80. This could distort your results in one of
907 several ways.
908 </para>
910 <para>It is possible that this other bug completely <quote>masks</quote> yours, which
911 is to say that it occurs before your bug has a chance to manifest
912 itself. If you can't avoid that other bug (for example, it prevents
913 your project from building), and so can't tell whether your bug is
914 present in a particular changeset, the <command role="hg-cmd">hg bisect</command> command cannot
915 help you directly. Instead, you can mark a changeset as untested by
916 running <command role="hg-cmd">hg bisect --skip</command>.
917 </para>
919 <para>A different problem could arise if your test for a bug's presence is
920 not specific enough. If you check for <quote>my program crashes</quote>, then
921 both your crashing bug and an unrelated crashing bug that masks it
922 will look like the same thing, and mislead <command role="hg-cmd">hg bisect</command>.
923 </para>
925 <para>Another useful situation in which to use <command role="hg-cmd">hg bisect --skip</command> is
926 if you can't test a revision because your project was in a broken and
927 hence untestable state at that revision, perhaps because someone
928 checked in a change that prevented the project from building.
929 </para>
931 </sect2>
932 <sect2>
933 <title>Bracket your search lazily</title>
935 <para>Choosing the first <quote>good</quote> and <quote>bad</quote> changesets that will mark the
936 end points of your search is often easy, but it bears a little
937 discussion nevertheless. From the perspective of <command role="hg-cmd">hg bisect</command>, the
938 <quote>newest</quote> changeset is conventionally <quote>bad</quote>, and the older
939 changeset is <quote>good</quote>.
940 </para>
942 <para>If you're having trouble remembering when a suitable <quote>good</quote> change
943 was, so that you can tell <command role="hg-cmd">hg bisect</command>, you could do worse than
944 testing changesets at random. Just remember to eliminate contenders
945 that can't possibly exhibit the bug (perhaps because the feature with
946 the bug isn't present yet) and those where another problem masks the
947 bug (as I discussed above).
948 </para>
950 <para>Even if you end up <quote>early</quote> by thousands of changesets or months of
951 history, you will only add a handful of tests to the total number that
952 <command role="hg-cmd">hg bisect</command> must perform, thanks to its logarithmic behaviour.
953 </para>
955 </sect2>
956 </sect1>
957 </chapter>
959 <!--
960 local variables:
961 sgml-parent-document: ("00book.xml" "book" "chapter")
962 end:
963 -->