hgbook
diff en/ch08-undo.xml @ 653:6b1577ef5135
Update Chinese translation
author | Dongsheng Song <dongsheng.song@gmail.com> |
---|---|
date | Fri Mar 20 17:17:55 2009 +0800 (2009-03-20) |
parents | a13813534ccd |
children | 1c13ed2130a7 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/en/ch08-undo.xml Fri Mar 20 17:17:55 2009 +0800 1.3 @@ -0,0 +1,1083 @@ 1.4 +<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : --> 1.5 + 1.6 +<chapter id="chap.undo"> 1.7 + <?dbhtml filename="finding-and-fixing-mistakes.html"?> 1.8 + <title>Finding and fixing mistakes</title> 1.9 + 1.10 + <para>To err might be human, but to really handle the consequences 1.11 + well takes a top-notch revision control system. In this chapter, 1.12 + we'll discuss some of the techniques you can use when you find 1.13 + that a problem has crept into your project. Mercurial has some 1.14 + highly capable features that will help you to isolate the sources 1.15 + of problems, and to handle them appropriately.</para> 1.16 + 1.17 + <sect1> 1.18 + <title>Erasing local history</title> 1.19 + 1.20 + <sect2> 1.21 + <title>The accidental commit</title> 1.22 + 1.23 + <para>I have the occasional but persistent problem of typing 1.24 + rather more quickly than I can think, which sometimes results 1.25 + in me committing a changeset that is either incomplete or 1.26 + plain wrong. In my case, the usual kind of incomplete 1.27 + changeset is one in which I've created a new source file, but 1.28 + forgotten to <command role="hg-cmd">hg add</command> it. A 1.29 + <quote>plain wrong</quote> changeset is not as common, but no 1.30 + less annoying.</para> 1.31 + 1.32 + </sect2> 1.33 + <sect2 id="sec.undo.rollback"> 1.34 + <title>Rolling back a transaction</title> 1.35 + 1.36 + <para>In section <xref linkend="sec.concepts.txn"/>, I mentioned 1.37 + that Mercurial treats each modification of a repository as a 1.38 + <emphasis>transaction</emphasis>. Every time you commit a 1.39 + changeset or pull changes from another repository, Mercurial 1.40 + remembers what you did. You can undo, or <emphasis>roll 1.41 + back</emphasis>, exactly one of these actions using the 1.42 + <command role="hg-cmd">hg rollback</command> command. (See 1.43 + section <xref linkend="sec.undo.rollback-after-push"/> for an 1.44 + important caveat about the use of this command.)</para> 1.45 + 1.46 + <para>Here's a mistake that I often find myself making: 1.47 + committing a change in which I've created a new file, but 1.48 + forgotten to <command role="hg-cmd">hg add</command> 1.49 + it.</para> 1.50 + 1.51 + &interaction.rollback.commit; 1.52 + 1.53 + <para>Looking at the output of <command role="hg-cmd">hg 1.54 + status</command> after the commit immediately confirms the 1.55 + error.</para> 1.56 + 1.57 + &interaction.rollback.status; 1.58 + 1.59 + <para>The commit captured the changes to the file 1.60 + <filename>a</filename>, but not the new file 1.61 + <filename>b</filename>. If I were to push this changeset to a 1.62 + repository that I shared with a colleague, the chances are 1.63 + high that something in <filename>a</filename> would refer to 1.64 + <filename>b</filename>, which would not be present in their 1.65 + repository when they pulled my changes. I would thus become 1.66 + the object of some indignation.</para> 1.67 + 1.68 + <para>However, luck is with me&emdash;I've caught my error 1.69 + before I pushed the changeset. I use the <command 1.70 + role="hg-cmd">hg rollback</command> command, and Mercurial 1.71 + makes that last changeset vanish.</para> 1.72 + 1.73 + &interaction.rollback.rollback; 1.74 + 1.75 + <para>Notice that the changeset is no longer present in the 1.76 + repository's history, and the working directory once again 1.77 + thinks that the file <filename>a</filename> is modified. The 1.78 + commit and rollback have left the working directory exactly as 1.79 + it was prior to the commit; the changeset has been completely 1.80 + erased. I can now safely <command role="hg-cmd">hg 1.81 + add</command> the file <filename>b</filename>, and rerun my 1.82 + commit.</para> 1.83 + 1.84 + &interaction.rollback.add; 1.85 + 1.86 + </sect2> 1.87 + <sect2> 1.88 + <title>The erroneous pull</title> 1.89 + 1.90 + <para>It's common practice with Mercurial to maintain separate 1.91 + development branches of a project in different repositories. 1.92 + Your development team might have one shared repository for 1.93 + your project's <quote>0.9</quote> release, and another, 1.94 + containing different changes, for the <quote>1.0</quote> 1.95 + release.</para> 1.96 + 1.97 + <para>Given this, you can imagine that the consequences could be 1.98 + messy if you had a local <quote>0.9</quote> repository, and 1.99 + accidentally pulled changes from the shared <quote>1.0</quote> 1.100 + repository into it. At worst, you could be paying 1.101 + insufficient attention, and push those changes into the shared 1.102 + <quote>0.9</quote> tree, confusing your entire team (but don't 1.103 + worry, we'll return to this horror scenario later). However, 1.104 + it's more likely that you'll notice immediately, because 1.105 + Mercurial will display the URL it's pulling from, or you will 1.106 + see it pull a suspiciously large number of changes into the 1.107 + repository.</para> 1.108 + 1.109 + <para>The <command role="hg-cmd">hg rollback</command> command 1.110 + will work nicely to expunge all of the changesets that you 1.111 + just pulled. Mercurial groups all changes from one <command 1.112 + role="hg-cmd">hg pull</command> into a single transaction, 1.113 + so one <command role="hg-cmd">hg rollback</command> is all you 1.114 + need to undo this mistake.</para> 1.115 + 1.116 + </sect2> 1.117 + <sect2 id="sec.undo.rollback-after-push"> 1.118 + <title>Rolling back is useless once you've pushed</title> 1.119 + 1.120 + <para>The value of the <command role="hg-cmd">hg 1.121 + rollback</command> command drops to zero once you've pushed 1.122 + your changes to another repository. Rolling back a change 1.123 + makes it disappear entirely, but <emphasis>only</emphasis> in 1.124 + the repository in which you perform the <command 1.125 + role="hg-cmd">hg rollback</command>. Because a rollback 1.126 + eliminates history, there's no way for the disappearance of a 1.127 + change to propagate between repositories.</para> 1.128 + 1.129 + <para>If you've pushed a change to another 1.130 + repository&emdash;particularly if it's a shared 1.131 + repository&emdash;it has essentially <quote>escaped into the 1.132 + wild,</quote> and you'll have to recover from your mistake 1.133 + in a different way. What will happen if you push a changeset 1.134 + somewhere, then roll it back, then pull from the repository 1.135 + you pushed to, is that the changeset will reappear in your 1.136 + repository.</para> 1.137 + 1.138 + <para>(If you absolutely know for sure that the change you want 1.139 + to roll back is the most recent change in the repository that 1.140 + you pushed to, <emphasis>and</emphasis> you know that nobody 1.141 + else could have pulled it from that repository, you can roll 1.142 + back the changeset there, too, but you really should really 1.143 + not rely on this working reliably. If you do this, sooner or 1.144 + later a change really will make it into a repository that you 1.145 + don't directly control (or have forgotten about), and come 1.146 + back to bite you.)</para> 1.147 + 1.148 + </sect2> 1.149 + <sect2> 1.150 + <title>You can only roll back once</title> 1.151 + 1.152 + <para>Mercurial stores exactly one transaction in its 1.153 + transaction log; that transaction is the most recent one that 1.154 + occurred in the repository. This means that you can only roll 1.155 + back one transaction. If you expect to be able to roll back 1.156 + one transaction, then its predecessor, this is not the 1.157 + behaviour you will get.</para> 1.158 + 1.159 + &interaction.rollback.twice; 1.160 + 1.161 + <para>Once you've rolled back one transaction in a repository, 1.162 + you can't roll back again in that repository until you perform 1.163 + another commit or pull.</para> 1.164 + 1.165 + </sect2> 1.166 + </sect1> 1.167 + <sect1> 1.168 + <title>Reverting the mistaken change</title> 1.169 + 1.170 + <para>If you make a modification to a file, and decide that you 1.171 + really didn't want to change the file at all, and you haven't 1.172 + yet committed your changes, the <command role="hg-cmd">hg 1.173 + revert</command> command is the one you'll need. It looks at 1.174 + the changeset that's the parent of the working directory, and 1.175 + restores the contents of the file to their state as of that 1.176 + changeset. (That's a long-winded way of saying that, in the 1.177 + normal case, it undoes your modifications.)</para> 1.178 + 1.179 + <para>Let's illustrate how the <command role="hg-cmd">hg 1.180 + revert</command> command works with yet another small example. 1.181 + We'll begin by modifying a file that Mercurial is already 1.182 + tracking.</para> 1.183 + 1.184 + &interaction.daily.revert.modify; 1.185 + 1.186 + <para>If we don't 1.187 + want that change, we can simply <command role="hg-cmd">hg 1.188 + revert</command> the file.</para> 1.189 + 1.190 + &interaction.daily.revert.unmodify; 1.191 + 1.192 + <para>The <command role="hg-cmd">hg revert</command> command 1.193 + provides us with an extra degree of safety by saving our 1.194 + modified file with a <filename>.orig</filename> 1.195 + extension.</para> 1.196 + 1.197 + &interaction.daily.revert.status; 1.198 + 1.199 + <para>Here is a summary of the cases that the <command 1.200 + role="hg-cmd">hg revert</command> command can deal with. We 1.201 + will describe each of these in more detail in the section that 1.202 + follows.</para> 1.203 + <itemizedlist> 1.204 + <listitem><para>If you modify a file, it will restore the file 1.205 + to its unmodified state.</para> 1.206 + </listitem> 1.207 + <listitem><para>If you <command role="hg-cmd">hg add</command> a 1.208 + file, it will undo the <quote>added</quote> state of the 1.209 + file, but leave the file itself untouched.</para> 1.210 + </listitem> 1.211 + <listitem><para>If you delete a file without telling Mercurial, 1.212 + it will restore the file to its unmodified contents.</para> 1.213 + </listitem> 1.214 + <listitem><para>If you use the <command role="hg-cmd">hg 1.215 + remove</command> command to remove a file, it will undo 1.216 + the <quote>removed</quote> state of the file, and restore 1.217 + the file to its unmodified contents.</para> 1.218 + </listitem></itemizedlist> 1.219 + 1.220 + <sect2 id="sec.undo.mgmt"> 1.221 + <title>File management errors</title> 1.222 + 1.223 + <para>The <command role="hg-cmd">hg revert</command> command is 1.224 + useful for more than just modified files. It lets you reverse 1.225 + the results of all of Mercurial's file management 1.226 + commands&emdash;<command role="hg-cmd">hg add</command>, 1.227 + <command role="hg-cmd">hg remove</command>, and so on.</para> 1.228 + 1.229 + <para>If you <command role="hg-cmd">hg add</command> a file, 1.230 + then decide that in fact you don't want Mercurial to track it, 1.231 + use <command role="hg-cmd">hg revert</command> to undo the 1.232 + add. Don't worry; Mercurial will not modify the file in any 1.233 + way. It will just <quote>unmark</quote> the file.</para> 1.234 + 1.235 + &interaction.daily.revert.add; 1.236 + 1.237 + <para>Similarly, if you ask Mercurial to <command 1.238 + role="hg-cmd">hg remove</command> a file, you can use 1.239 + <command role="hg-cmd">hg revert</command> to restore it to 1.240 + the contents it had as of the parent of the working directory. 1.241 + &interaction.daily.revert.remove; This works just as 1.242 + well for a file that you deleted by hand, without telling 1.243 + Mercurial (recall that in Mercurial terminology, this kind of 1.244 + file is called <quote>missing</quote>).</para> 1.245 + 1.246 + &interaction.daily.revert.missing; 1.247 + 1.248 + <para>If you revert a <command role="hg-cmd">hg copy</command>, 1.249 + the copied-to file remains in your working directory 1.250 + afterwards, untracked. Since a copy doesn't affect the 1.251 + copied-from file in any way, Mercurial doesn't do anything 1.252 + with the copied-from file.</para> 1.253 + 1.254 + &interaction.daily.revert.copy; 1.255 + 1.256 + <sect3> 1.257 + <title>A slightly special case: reverting a rename</title> 1.258 + 1.259 + <para>If you <command role="hg-cmd">hg rename</command> a 1.260 + file, there is one small detail that you should remember. 1.261 + When you <command role="hg-cmd">hg revert</command> a 1.262 + rename, it's not enough to provide the name of the 1.263 + renamed-to file, as you can see here.</para> 1.264 + 1.265 + &interaction.daily.revert.rename; 1.266 + 1.267 + <para>As you can see from the output of <command 1.268 + role="hg-cmd">hg status</command>, the renamed-to file is 1.269 + no longer identified as added, but the 1.270 + renamed-<emphasis>from</emphasis> file is still removed! 1.271 + This is counter-intuitive (at least to me), but at least 1.272 + it's easy to deal with.</para> 1.273 + 1.274 + &interaction.daily.revert.rename-orig; 1.275 + 1.276 + <para>So remember, to revert a <command role="hg-cmd">hg 1.277 + rename</command>, you must provide 1.278 + <emphasis>both</emphasis> the source and destination 1.279 + names.</para> 1.280 + 1.281 + <para>% TODO: the output doesn't look like it will be 1.282 + removed!</para> 1.283 + 1.284 + <para>(By the way, if you rename a file, then modify the 1.285 + renamed-to file, then revert both components of the rename, 1.286 + when Mercurial restores the file that was removed as part of 1.287 + the rename, it will be unmodified. If you need the 1.288 + modifications in the renamed-to file to show up in the 1.289 + renamed-from file, don't forget to copy them over.)</para> 1.290 + 1.291 + <para>These fiddly aspects of reverting a rename arguably 1.292 + constitute a small bug in Mercurial.</para> 1.293 + 1.294 + </sect3> 1.295 + </sect2> 1.296 + </sect1> 1.297 + <sect1> 1.298 + <title>Dealing with committed changes</title> 1.299 + 1.300 + <para>Consider a case where you have committed a change $a$, and 1.301 + another change $b$ on top of it; you then realise that change 1.302 + $a$ was incorrect. Mercurial lets you <quote>back out</quote> 1.303 + an entire changeset automatically, and building blocks that let 1.304 + you reverse part of a changeset by hand.</para> 1.305 + 1.306 + <para>Before you read this section, here's something to keep in 1.307 + mind: the <command role="hg-cmd">hg backout</command> command 1.308 + undoes changes by <emphasis>adding</emphasis> history, not by 1.309 + modifying or erasing it. It's the right tool to use if you're 1.310 + fixing bugs, but not if you're trying to undo some change that 1.311 + has catastrophic consequences. To deal with those, see section 1.312 + <xref linkend="sec.undo.aaaiiieee"/>.</para> 1.313 + 1.314 + <sect2> 1.315 + <title>Backing out a changeset</title> 1.316 + 1.317 + <para>The <command role="hg-cmd">hg backout</command> command 1.318 + lets you <quote>undo</quote> the effects of an entire 1.319 + changeset in an automated fashion. Because Mercurial's 1.320 + history is immutable, this command <emphasis>does 1.321 + not</emphasis> get rid of the changeset you want to undo. 1.322 + Instead, it creates a new changeset that 1.323 + <emphasis>reverses</emphasis> the effect of the to-be-undone 1.324 + changeset.</para> 1.325 + 1.326 + <para>The operation of the <command role="hg-cmd">hg 1.327 + backout</command> command is a little intricate, so let's 1.328 + illustrate it with some examples. First, we'll create a 1.329 + repository with some simple changes.</para> 1.330 + 1.331 + &interaction.backout.init; 1.332 + 1.333 + <para>The <command role="hg-cmd">hg backout</command> command 1.334 + takes a single changeset ID as its argument; this is the 1.335 + changeset to back out. Normally, <command role="hg-cmd">hg 1.336 + backout</command> will drop you into a text editor to write 1.337 + a commit message, so you can record why you're backing the 1.338 + change out. In this example, we provide a commit message on 1.339 + the command line using the <option 1.340 + role="hg-opt-backout">-m</option> option.</para> 1.341 + 1.342 + </sect2> 1.343 + <sect2> 1.344 + <title>Backing out the tip changeset</title> 1.345 + 1.346 + <para>We're going to start by backing out the last changeset we 1.347 + committed.</para> 1.348 + 1.349 + &interaction.backout.simple; 1.350 + 1.351 + <para>You can see that the second line from 1.352 + <filename>myfile</filename> is no longer present. Taking a 1.353 + look at the output of <command role="hg-cmd">hg log</command> 1.354 + gives us an idea of what the <command role="hg-cmd">hg 1.355 + backout</command> command has done. 1.356 + &interaction.backout.simple.log; Notice that the new changeset 1.357 + that <command role="hg-cmd">hg backout</command> has created 1.358 + is a child of the changeset we backed out. It's easier to see 1.359 + this in figure <xref 1.360 + endterm="fig.undo.backout.caption" linkend="fig.undo.backout"/>, 1.361 + which presents a graphical 1.362 + view of the change history. As you can see, the history is 1.363 + nice and linear.</para> 1.364 + 1.365 + <informalfigure id="fig.undo.backout"> 1.366 + <mediaobject> 1.367 + <imageobject><imagedata fileref="images/undo-simple.png"/> 1.368 + </imageobject> 1.369 + <textobject><phrase>XXX add text</phrase></textobject> 1.370 + <caption><para id="fig.undo.backout.caption">Backing out 1.371 + a change using the 1.372 + <command role="hg-cmd">hg backout</command> 1.373 + command</para></caption> 1.374 + </mediaobject> 1.375 + </informalfigure> 1.376 + 1.377 + </sect2> 1.378 + <sect2> 1.379 + <title>Backing out a non-tip change</title> 1.380 + 1.381 + <para>If you want to back out a change other than the last one 1.382 + you committed, pass the <option 1.383 + role="hg-opt-backout">--merge</option> option to the 1.384 + <command role="hg-cmd">hg backout</command> command.</para> 1.385 + 1.386 + &interaction.backout.non-tip.clone; 1.387 + 1.388 + <para>This makes backing out any changeset a 1.389 + <quote>one-shot</quote> operation that's usually simple and 1.390 + fast.</para> 1.391 + 1.392 + &interaction.backout.non-tip.backout; 1.393 + 1.394 + <para>If you take a look at the contents of 1.395 + <filename>myfile</filename> after the backout finishes, you'll 1.396 + see that the first and third changes are present, but not the 1.397 + second.</para> 1.398 + 1.399 + &interaction.backout.non-tip.cat; 1.400 + 1.401 + <para>As the graphical history in figure <xref 1.402 + endterm="fig.undo.backout-non-tip.caption" 1.403 + linkend="fig.undo.backout-non-tip"/> illustrates, Mercurial 1.404 + actually commits <emphasis>two</emphasis> changes in this kind 1.405 + of situation (the box-shaped nodes are the ones that Mercurial 1.406 + commits automatically). Before Mercurial begins the backout 1.407 + process, it first remembers what the current parent of the 1.408 + working directory is. It then backs out the target changeset, 1.409 + and commits that as a changeset. Finally, it merges back to 1.410 + the previous parent of the working directory, and commits the 1.411 + result of the merge.</para> 1.412 + 1.413 + <para>% TODO: to me it looks like mercurial doesn't commit the 1.414 + second merge automatically!</para> 1.415 + 1.416 + <informalfigure id="fig.undo.backout-non-tip"> 1.417 + <mediaobject> 1.418 + <imageobject><imagedata fileref="images/undo-non-tip.png"/> 1.419 + </imageobject> 1.420 + <textobject><phrase>XXX add text</phrase></textobject> 1.421 + <caption><para id="fig.undo.backout-non-tip.caption">Automated 1.422 + backout of a non-tip change using the 1.423 + <command role="hg-cmd">hg backout</command> command</para></caption> 1.424 + </mediaobject> 1.425 + </informalfigure> 1.426 + 1.427 + <para>The result is that you end up <quote>back where you 1.428 + were</quote>, only with some extra history that undoes the 1.429 + effect of the changeset you wanted to back out.</para> 1.430 + 1.431 + <sect3> 1.432 + <title>Always use the <option 1.433 + role="hg-opt-backout">--merge</option> option</title> 1.434 + 1.435 + <para>In fact, since the <option 1.436 + role="hg-opt-backout">--merge</option> option will do the 1.437 + <quote>right thing</quote> whether or not the changeset 1.438 + you're backing out is the tip (i.e. it won't try to merge if 1.439 + it's backing out the tip, since there's no need), you should 1.440 + <emphasis>always</emphasis> use this option when you run the 1.441 + <command role="hg-cmd">hg backout</command> command.</para> 1.442 + 1.443 + </sect3> 1.444 + </sect2> 1.445 + <sect2> 1.446 + <title>Gaining more control of the backout process</title> 1.447 + 1.448 + <para>While I've recommended that you always use the <option 1.449 + role="hg-opt-backout">--merge</option> option when backing 1.450 + out a change, the <command role="hg-cmd">hg backout</command> 1.451 + command lets you decide how to merge a backout changeset. 1.452 + Taking control of the backout process by hand is something you 1.453 + will rarely need to do, but it can be useful to understand 1.454 + what the <command role="hg-cmd">hg backout</command> command 1.455 + is doing for you automatically. To illustrate this, let's 1.456 + clone our first repository, but omit the backout change that 1.457 + it contains.</para> 1.458 + 1.459 + &interaction.backout.manual.clone; 1.460 + 1.461 + <para>As with our 1.462 + earlier example, We'll commit a third changeset, then back out 1.463 + its parent, and see what happens.</para> 1.464 + 1.465 + &interaction.backout.manual.backout; 1.466 + 1.467 + <para>Our new changeset is again a descendant of the changeset 1.468 + we backout out; it's thus a new head, <emphasis>not</emphasis> 1.469 + a descendant of the changeset that was the tip. The <command 1.470 + role="hg-cmd">hg backout</command> command was quite 1.471 + explicit in telling us this.</para> 1.472 + 1.473 + &interaction.backout.manual.log; 1.474 + 1.475 + <para>Again, it's easier to see what has happened by looking at 1.476 + a graph of the revision history, in figure <xref 1.477 + endterm="fig.undo.backout-manual.caption" 1.478 + linkend="fig.undo.backout-manual"/>. This makes it clear 1.479 + that when we use <command role="hg-cmd">hg backout</command> 1.480 + to back out a change other than the tip, Mercurial adds a new 1.481 + head to the repository (the change it committed is 1.482 + box-shaped).</para> 1.483 + 1.484 + <informalfigure id="fig.undo.backout-manual"> 1.485 + <mediaobject> 1.486 + <imageobject><imagedata fileref="images/undo-manual.png"/> 1.487 + </imageobject> 1.488 + <textobject><phrase>XXX add text</phrase></textobject> 1.489 + <caption><para id="fig.undo.backout-manual.caption">Backing out a 1.490 + change using the <command role="hg-cmd">hg backout</command> 1.491 + command</para></caption> 1.492 + </mediaobject> 1.493 + </informalfigure> 1.494 + 1.495 + <para>After the <command role="hg-cmd">hg backout</command> 1.496 + command has completed, it leaves the new 1.497 + <quote>backout</quote> changeset as the parent of the working 1.498 + directory.</para> 1.499 + 1.500 + &interaction.backout.manual.parents; 1.501 + 1.502 + <para>Now we have two isolated sets of changes.</para> 1.503 + 1.504 + &interaction.backout.manual.heads; 1.505 + 1.506 + <para>Let's think about what we expect to see as the contents of 1.507 + <filename>myfile</filename> now. The first change should be 1.508 + present, because we've never backed it out. The second change 1.509 + should be missing, as that's the change we backed out. Since 1.510 + the history graph shows the third change as a separate head, 1.511 + we <emphasis>don't</emphasis> expect to see the third change 1.512 + present in <filename>myfile</filename>.</para> 1.513 + 1.514 + &interaction.backout.manual.cat; 1.515 + 1.516 + <para>To get the third change back into the file, we just do a 1.517 + normal merge of our two heads.</para> 1.518 + 1.519 + &interaction.backout.manual.merge; 1.520 + 1.521 + <para>Afterwards, the graphical history of our repository looks 1.522 + like figure 1.523 + <xref endterm="fig.undo.backout-manual-merge.caption" 1.524 + linkend="fig.undo.backout-manual-merge"/>.</para> 1.525 + 1.526 + <informalfigure id="fig.undo.backout-manual-merge"> 1.527 + <mediaobject> 1.528 + <imageobject><imagedata fileref="images/undo-manual-merge.png"/> 1.529 + </imageobject> 1.530 + <textobject><phrase>XXX add text</phrase></textobject> 1.531 + <caption><para id="fig.undo.backout-manual-merge.caption">Manually 1.532 + merging a backout change</para></caption> 1.533 + </mediaobject> 1.534 + </informalfigure> 1.535 + 1.536 + </sect2> 1.537 + <sect2> 1.538 + <title>Why <command role="hg-cmd">hg backout</command> works as 1.539 + it does</title> 1.540 + 1.541 + <para>Here's a brief description of how the <command 1.542 + role="hg-cmd">hg backout</command> command works.</para> 1.543 + <orderedlist> 1.544 + <listitem><para>It ensures that the working directory is 1.545 + <quote>clean</quote>, i.e. that the output of <command 1.546 + role="hg-cmd">hg status</command> would be empty.</para> 1.547 + </listitem> 1.548 + <listitem><para>It remembers the current parent of the working 1.549 + directory. Let's call this changeset 1.550 + <literal>orig</literal></para> 1.551 + </listitem> 1.552 + <listitem><para>It does the equivalent of a <command 1.553 + role="hg-cmd">hg update</command> to sync the working 1.554 + directory to the changeset you want to back out. Let's 1.555 + call this changeset <literal>backout</literal></para> 1.556 + </listitem> 1.557 + <listitem><para>It finds the parent of that changeset. Let's 1.558 + call that changeset <literal>parent</literal>.</para> 1.559 + </listitem> 1.560 + <listitem><para>For each file that the 1.561 + <literal>backout</literal> changeset affected, it does the 1.562 + equivalent of a <command role="hg-cmd">hg revert -r 1.563 + parent</command> on that file, to restore it to the 1.564 + contents it had before that changeset was 1.565 + committed.</para> 1.566 + </listitem> 1.567 + <listitem><para>It commits the result as a new changeset. 1.568 + This changeset has <literal>backout</literal> as its 1.569 + parent.</para> 1.570 + </listitem> 1.571 + <listitem><para>If you specify <option 1.572 + role="hg-opt-backout">--merge</option> on the command 1.573 + line, it merges with <literal>orig</literal>, and commits 1.574 + the result of the merge.</para> 1.575 + </listitem></orderedlist> 1.576 + 1.577 + <para>An alternative way to implement the <command 1.578 + role="hg-cmd">hg backout</command> command would be to 1.579 + <command role="hg-cmd">hg export</command> the 1.580 + to-be-backed-out changeset as a diff, then use the <option 1.581 + role="cmd-opt-patch">--reverse</option> option to the 1.582 + <command>patch</command> command to reverse the effect of the 1.583 + change without fiddling with the working directory. This 1.584 + sounds much simpler, but it would not work nearly as 1.585 + well.</para> 1.586 + 1.587 + <para>The reason that <command role="hg-cmd">hg 1.588 + backout</command> does an update, a commit, a merge, and 1.589 + another commit is to give the merge machinery the best chance 1.590 + to do a good job when dealing with all the changes 1.591 + <emphasis>between</emphasis> the change you're backing out and 1.592 + the current tip.</para> 1.593 + 1.594 + <para>If you're backing out a changeset that's 100 revisions 1.595 + back in your project's history, the chances that the 1.596 + <command>patch</command> command will be able to apply a 1.597 + reverse diff cleanly are not good, because intervening changes 1.598 + are likely to have <quote>broken the context</quote> that 1.599 + <command>patch</command> uses to determine whether it can 1.600 + apply a patch (if this sounds like gibberish, see <xref 1.601 + linkend="sec.mq.patch"/> for a 1.602 + discussion of the <command>patch</command> command). Also, 1.603 + Mercurial's merge machinery will handle files and directories 1.604 + being renamed, permission changes, and modifications to binary 1.605 + files, none of which <command>patch</command> can deal 1.606 + with.</para> 1.607 + 1.608 + </sect2> 1.609 + </sect1> 1.610 + <sect1 id="sec.undo.aaaiiieee"> 1.611 + <title>Changes that should never have been</title> 1.612 + 1.613 + <para>Most of the time, the <command role="hg-cmd">hg 1.614 + backout</command> command is exactly what you need if you want 1.615 + to undo the effects of a change. It leaves a permanent record 1.616 + of exactly what you did, both when committing the original 1.617 + changeset and when you cleaned up after it.</para> 1.618 + 1.619 + <para>On rare occasions, though, you may find that you've 1.620 + committed a change that really should not be present in the 1.621 + repository at all. For example, it would be very unusual, and 1.622 + usually considered a mistake, to commit a software project's 1.623 + object files as well as its source files. Object files have 1.624 + almost no intrinsic value, and they're <emphasis>big</emphasis>, 1.625 + so they increase the size of the repository and the amount of 1.626 + time it takes to clone or pull changes.</para> 1.627 + 1.628 + <para>Before I discuss the options that you have if you commit a 1.629 + <quote>brown paper bag</quote> change (the kind that's so bad 1.630 + that you want to pull a brown paper bag over your head), let me 1.631 + first discuss some approaches that probably won't work.</para> 1.632 + 1.633 + <para>Since Mercurial treats history as accumulative&emdash;every 1.634 + change builds on top of all changes that preceded it&emdash;you 1.635 + generally can't just make disastrous changes disappear. The one 1.636 + exception is when you've just committed a change, and it hasn't 1.637 + been pushed or pulled into another repository. That's when you 1.638 + can safely use the <command role="hg-cmd">hg rollback</command> 1.639 + command, as I detailed in section <xref 1.640 + linkend="sec.undo.rollback"/>.</para> 1.641 + 1.642 + <para>After you've pushed a bad change to another repository, you 1.643 + <emphasis>could</emphasis> still use <command role="hg-cmd">hg 1.644 + rollback</command> to make your local copy of the change 1.645 + disappear, but it won't have the consequences you want. The 1.646 + change will still be present in the remote repository, so it 1.647 + will reappear in your local repository the next time you 1.648 + pull.</para> 1.649 + 1.650 + <para>If a situation like this arises, and you know which 1.651 + repositories your bad change has propagated into, you can 1.652 + <emphasis>try</emphasis> to get rid of the changeefrom 1.653 + <emphasis>every</emphasis> one of those repositories. This is, 1.654 + of course, not a satisfactory solution: if you miss even a 1.655 + single repository while you're expunging, the change is still 1.656 + <quote>in the wild</quote>, and could propagate further.</para> 1.657 + 1.658 + <para>If you've committed one or more changes 1.659 + <emphasis>after</emphasis> the change that you'd like to see 1.660 + disappear, your options are further reduced. Mercurial doesn't 1.661 + provide a way to <quote>punch a hole</quote> in history, leaving 1.662 + changesets intact.</para> 1.663 + 1.664 + <para>XXX This needs filling out. The 1.665 + <literal>hg-replay</literal> script in the 1.666 + <literal>examples</literal> directory works, but doesn't handle 1.667 + merge changesets. Kind of an important omission.</para> 1.668 + 1.669 + <sect2> 1.670 + <title>Protect yourself from <quote>escaped</quote> 1.671 + changes</title> 1.672 + 1.673 + <para>If you've committed some changes to your local repository 1.674 + and they've been pushed or pulled somewhere else, this isn't 1.675 + necessarily a disaster. You can protect yourself ahead of 1.676 + time against some classes of bad changeset. This is 1.677 + particularly easy if your team usually pulls changes from a 1.678 + central repository.</para> 1.679 + 1.680 + <para>By configuring some hooks on that repository to validate 1.681 + incoming changesets (see chapter <xref linkend="chap.hook"/>), 1.682 + you can 1.683 + automatically prevent some kinds of bad changeset from being 1.684 + pushed to the central repository at all. With such a 1.685 + configuration in place, some kinds of bad changeset will 1.686 + naturally tend to <quote>die out</quote> because they can't 1.687 + propagate into the central repository. Better yet, this 1.688 + happens without any need for explicit intervention.</para> 1.689 + 1.690 + <para>For instance, an incoming change hook that verifies that a 1.691 + changeset will actually compile can prevent people from 1.692 + inadvertantly <quote>breaking the build</quote>.</para> 1.693 + 1.694 + </sect2> 1.695 + </sect1> 1.696 + <sect1 id="sec.undo.bisect"> 1.697 + <title>Finding the source of a bug</title> 1.698 + 1.699 + <para>While it's all very well to be able to back out a changeset 1.700 + that introduced a bug, this requires that you know which 1.701 + changeset to back out. Mercurial provides an invaluable 1.702 + command, called <command role="hg-cmd">hg bisect</command>, that 1.703 + helps you to automate this process and accomplish it very 1.704 + efficiently.</para> 1.705 + 1.706 + <para>The idea behind the <command role="hg-cmd">hg 1.707 + bisect</command> command is that a changeset has introduced 1.708 + some change of behaviour that you can identify with a simple 1.709 + binary test. You don't know which piece of code introduced the 1.710 + change, but you know how to test for the presence of the bug. 1.711 + The <command role="hg-cmd">hg bisect</command> command uses your 1.712 + test to direct its search for the changeset that introduced the 1.713 + code that caused the bug.</para> 1.714 + 1.715 + <para>Here are a few scenarios to help you understand how you 1.716 + might apply this command.</para> 1.717 + <itemizedlist> 1.718 + <listitem><para>The most recent version of your software has a 1.719 + bug that you remember wasn't present a few weeks ago, but 1.720 + you don't know when it was introduced. Here, your binary 1.721 + test checks for the presence of that bug.</para> 1.722 + </listitem> 1.723 + <listitem><para>You fixed a bug in a rush, and now it's time to 1.724 + close the entry in your team's bug database. The bug 1.725 + database requires a changeset ID when you close an entry, 1.726 + but you don't remember which changeset you fixed the bug in. 1.727 + Once again, your binary test checks for the presence of the 1.728 + bug.</para> 1.729 + </listitem> 1.730 + <listitem><para>Your software works correctly, but runs 15% 1.731 + slower than the last time you measured it. You want to know 1.732 + which changeset introduced the performance regression. In 1.733 + this case, your binary test measures the performance of your 1.734 + software, to see whether it's <quote>fast</quote> or 1.735 + <quote>slow</quote>.</para> 1.736 + </listitem> 1.737 + <listitem><para>The sizes of the components of your project that 1.738 + you ship exploded recently, and you suspect that something 1.739 + changed in the way you build your project.</para> 1.740 + </listitem></itemizedlist> 1.741 + 1.742 + <para>From these examples, it should be clear that the <command 1.743 + role="hg-cmd">hg bisect</command> command is not useful only 1.744 + for finding the sources of bugs. You can use it to find any 1.745 + <quote>emergent property</quote> of a repository (anything that 1.746 + you can't find from a simple text search of the files in the 1.747 + tree) for which you can write a binary test.</para> 1.748 + 1.749 + <para>We'll introduce a little bit of terminology here, just to 1.750 + make it clear which parts of the search process are your 1.751 + responsibility, and which are Mercurial's. A 1.752 + <emphasis>test</emphasis> is something that 1.753 + <emphasis>you</emphasis> run when <command role="hg-cmd">hg 1.754 + bisect</command> chooses a changeset. A 1.755 + <emphasis>probe</emphasis> is what <command role="hg-cmd">hg 1.756 + bisect</command> runs to tell whether a revision is good. 1.757 + Finally, we'll use the word <quote>bisect</quote>, as both a 1.758 + noun and a verb, to stand in for the phrase <quote>search using 1.759 + the <command role="hg-cmd">hg bisect</command> 1.760 + command</quote>.</para> 1.761 + 1.762 + <para>One simple way to automate the searching process would be 1.763 + simply to probe every changeset. However, this scales poorly. 1.764 + If it took ten minutes to test a single changeset, and you had 1.765 + 10,000 changesets in your repository, the exhaustive approach 1.766 + would take on average 35 <emphasis>days</emphasis> to find the 1.767 + changeset that introduced a bug. Even if you knew that the bug 1.768 + was introduced by one of the last 500 changesets, and limited 1.769 + your search to those, you'd still be looking at over 40 hours to 1.770 + find the changeset that introduced your bug.</para> 1.771 + 1.772 + <para>What the <command role="hg-cmd">hg bisect</command> command 1.773 + does is use its knowledge of the <quote>shape</quote> of your 1.774 + project's revision history to perform a search in time 1.775 + proportional to the <emphasis>logarithm</emphasis> of the number 1.776 + of changesets to check (the kind of search it performs is called 1.777 + a dichotomic search). With this approach, searching through 1.778 + 10,000 changesets will take less than three hours, even at ten 1.779 + minutes per test (the search will require about 14 tests). 1.780 + Limit your search to the last hundred changesets, and it will 1.781 + take only about an hour (roughly seven tests).</para> 1.782 + 1.783 + <para>The <command role="hg-cmd">hg bisect</command> command is 1.784 + aware of the <quote>branchy</quote> nature of a Mercurial 1.785 + project's revision history, so it has no problems dealing with 1.786 + branches, merges, or multiple heads in a repository. It can 1.787 + prune entire branches of history with a single probe, which is 1.788 + how it operates so efficiently.</para> 1.789 + 1.790 + <sect2> 1.791 + <title>Using the <command role="hg-cmd">hg bisect</command> 1.792 + command</title> 1.793 + 1.794 + <para>Here's an example of <command role="hg-cmd">hg 1.795 + bisect</command> in action.</para> 1.796 + 1.797 + <note> 1.798 + <para> In versions 0.9.5 and earlier of Mercurial, <command 1.799 + role="hg-cmd">hg bisect</command> was not a core command: 1.800 + it was distributed with Mercurial as an extension. This 1.801 + section describes the built-in command, not the old 1.802 + extension.</para> 1.803 + </note> 1.804 + 1.805 + <para>Now let's create a repository, so that we can try out the 1.806 + <command role="hg-cmd">hg bisect</command> command in 1.807 + isolation.</para> 1.808 + 1.809 + &interaction.bisect.init; 1.810 + 1.811 + <para>We'll simulate a project that has a bug in it in a 1.812 + simple-minded way: create trivial changes in a loop, and 1.813 + nominate one specific change that will have the 1.814 + <quote>bug</quote>. This loop creates 35 changesets, each 1.815 + adding a single file to the repository. We'll represent our 1.816 + <quote>bug</quote> with a file that contains the text <quote>i 1.817 + have a gub</quote>.</para> 1.818 + 1.819 + &interaction.bisect.commits; 1.820 + 1.821 + <para>The next thing that we'd like to do is figure out how to 1.822 + use the <command role="hg-cmd">hg bisect</command> command. 1.823 + We can use Mercurial's normal built-in help mechanism for 1.824 + this.</para> 1.825 + 1.826 + &interaction.bisect.help; 1.827 + 1.828 + <para>The <command role="hg-cmd">hg bisect</command> command 1.829 + works in steps. Each step proceeds as follows.</para> 1.830 + <orderedlist> 1.831 + <listitem><para>You run your binary test.</para> 1.832 + <itemizedlist> 1.833 + <listitem><para>If the test succeeded, you tell <command 1.834 + role="hg-cmd">hg bisect</command> by running the 1.835 + <command role="hg-cmd">hg bisect good</command> 1.836 + command.</para> 1.837 + </listitem> 1.838 + <listitem><para>If it failed, run the <command 1.839 + role="hg-cmd">hg bisect bad</command> 1.840 + command.</para></listitem></itemizedlist> 1.841 + </listitem> 1.842 + <listitem><para>The command uses your information to decide 1.843 + which changeset to test next.</para> 1.844 + </listitem> 1.845 + <listitem><para>It updates the working directory to that 1.846 + changeset, and the process begins again.</para> 1.847 + </listitem></orderedlist> 1.848 + <para>The process ends when <command role="hg-cmd">hg 1.849 + bisect</command> identifies a unique changeset that marks 1.850 + the point where your test transitioned from 1.851 + <quote>succeeding</quote> to <quote>failing</quote>.</para> 1.852 + 1.853 + <para>To start the search, we must run the <command 1.854 + role="hg-cmd">hg bisect --reset</command> command.</para> 1.855 + 1.856 + &interaction.bisect.search.init; 1.857 + 1.858 + <para>In our case, the binary test we use is simple: we check to 1.859 + see if any file in the repository contains the string <quote>i 1.860 + have a gub</quote>. If it does, this changeset contains the 1.861 + change that <quote>caused the bug</quote>. By convention, a 1.862 + changeset that has the property we're searching for is 1.863 + <quote>bad</quote>, while one that doesn't is 1.864 + <quote>good</quote>.</para> 1.865 + 1.866 + <para>Most of the time, the revision to which the working 1.867 + directory is synced (usually the tip) already exhibits the 1.868 + problem introduced by the buggy change, so we'll mark it as 1.869 + <quote>bad</quote>.</para> 1.870 + 1.871 + &interaction.bisect.search.bad-init; 1.872 + 1.873 + <para>Our next task is to nominate a changeset that we know 1.874 + <emphasis>doesn't</emphasis> have the bug; the <command 1.875 + role="hg-cmd">hg bisect</command> command will 1.876 + <quote>bracket</quote> its search between the first pair of 1.877 + good and bad changesets. In our case, we know that revision 1.878 + 10 didn't have the bug. (I'll have more words about choosing 1.879 + the first <quote>good</quote> changeset later.)</para> 1.880 + 1.881 + &interaction.bisect.search.good-init; 1.882 + 1.883 + <para>Notice that this command printed some output.</para> 1.884 + <itemizedlist> 1.885 + <listitem><para>It told us how many changesets it must 1.886 + consider before it can identify the one that introduced 1.887 + the bug, and how many tests that will require.</para> 1.888 + </listitem> 1.889 + <listitem><para>It updated the working directory to the next 1.890 + changeset to test, and told us which changeset it's 1.891 + testing.</para> 1.892 + </listitem></itemizedlist> 1.893 + 1.894 + <para>We now run our test in the working directory. We use the 1.895 + <command>grep</command> command to see if our 1.896 + <quote>bad</quote> file is present in the working directory. 1.897 + If it is, this revision is bad; if not, this revision is good. 1.898 + &interaction.bisect.search.step1;</para> 1.899 + 1.900 + <para>This test looks like a perfect candidate for automation, 1.901 + so let's turn it into a shell function.</para> 1.902 + &interaction.bisect.search.mytest; 1.903 + 1.904 + <para>We can now run an entire test step with a single command, 1.905 + <literal>mytest</literal>.</para> 1.906 + 1.907 + &interaction.bisect.search.step2; 1.908 + 1.909 + <para>A few more invocations of our canned test step command, 1.910 + and we're done.</para> 1.911 + 1.912 + &interaction.bisect.search.rest; 1.913 + 1.914 + <para>Even though we had 40 changesets to search through, the 1.915 + <command role="hg-cmd">hg bisect</command> command let us find 1.916 + the changeset that introduced our <quote>bug</quote> with only 1.917 + five tests. Because the number of tests that the <command 1.918 + role="hg-cmd">hg bisect</command> command performs grows 1.919 + logarithmically with the number of changesets to search, the 1.920 + advantage that it has over the <quote>brute force</quote> 1.921 + search approach increases with every changeset you add.</para> 1.922 + 1.923 + </sect2> 1.924 + <sect2> 1.925 + <title>Cleaning up after your search</title> 1.926 + 1.927 + <para>When you're finished using the <command role="hg-cmd">hg 1.928 + bisect</command> command in a repository, you can use the 1.929 + <command role="hg-cmd">hg bisect reset</command> command to 1.930 + drop the information it was using to drive your search. The 1.931 + command doesn't use much space, so it doesn't matter if you 1.932 + forget to run this command. However, <command 1.933 + role="hg-cmd">hg bisect</command> won't let you start a new 1.934 + search in that repository until you do a <command 1.935 + role="hg-cmd">hg bisect reset</command>.</para> 1.936 + 1.937 + &interaction.bisect.search.reset; 1.938 + 1.939 + </sect2> 1.940 + </sect1> 1.941 + <sect1> 1.942 + <title>Tips for finding bugs effectively</title> 1.943 + 1.944 + <sect2> 1.945 + <title>Give consistent input</title> 1.946 + 1.947 + <para>The <command role="hg-cmd">hg bisect</command> command 1.948 + requires that you correctly report the result of every test 1.949 + you perform. If you tell it that a test failed when it really 1.950 + succeeded, it <emphasis>might</emphasis> be able to detect the 1.951 + inconsistency. If it can identify an inconsistency in your 1.952 + reports, it will tell you that a particular changeset is both 1.953 + good and bad. However, it can't do this perfectly; it's about 1.954 + as likely to report the wrong changeset as the source of the 1.955 + bug.</para> 1.956 + 1.957 + </sect2> 1.958 + <sect2> 1.959 + <title>Automate as much as possible</title> 1.960 + 1.961 + <para>When I started using the <command role="hg-cmd">hg 1.962 + bisect</command> command, I tried a few times to run my 1.963 + tests by hand, on the command line. This is an approach that 1.964 + I, at least, am not suited to. After a few tries, I found 1.965 + that I was making enough mistakes that I was having to restart 1.966 + my searches several times before finally getting correct 1.967 + results.</para> 1.968 + 1.969 + <para>My initial problems with driving the <command 1.970 + role="hg-cmd">hg bisect</command> command by hand occurred 1.971 + even with simple searches on small repositories; if the 1.972 + problem you're looking for is more subtle, or the number of 1.973 + tests that <command role="hg-cmd">hg bisect</command> must 1.974 + perform increases, the likelihood of operator error ruining 1.975 + the search is much higher. Once I started automating my 1.976 + tests, I had much better results.</para> 1.977 + 1.978 + <para>The key to automated testing is twofold:</para> 1.979 + <itemizedlist> 1.980 + <listitem><para>always test for the same symptom, and</para> 1.981 + </listitem> 1.982 + <listitem><para>always feed consistent input to the <command 1.983 + role="hg-cmd">hg bisect</command> command.</para> 1.984 + </listitem></itemizedlist> 1.985 + <para>In my tutorial example above, the <command>grep</command> 1.986 + command tests for the symptom, and the <literal>if</literal> 1.987 + statement takes the result of this check and ensures that we 1.988 + always feed the same input to the <command role="hg-cmd">hg 1.989 + bisect</command> command. The <literal>mytest</literal> 1.990 + function marries these together in a reproducible way, so that 1.991 + every test is uniform and consistent.</para> 1.992 + 1.993 + </sect2> 1.994 + <sect2> 1.995 + <title>Check your results</title> 1.996 + 1.997 + <para>Because the output of a <command role="hg-cmd">hg 1.998 + bisect</command> search is only as good as the input you 1.999 + give it, don't take the changeset it reports as the absolute 1.1000 + truth. A simple way to cross-check its report is to manually 1.1001 + run your test at each of the following changesets:</para> 1.1002 + <itemizedlist> 1.1003 + <listitem><para>The changeset that it reports as the first bad 1.1004 + revision. Your test should still report this as 1.1005 + bad.</para> 1.1006 + </listitem> 1.1007 + <listitem><para>The parent of that changeset (either parent, 1.1008 + if it's a merge). Your test should report this changeset 1.1009 + as good.</para> 1.1010 + </listitem> 1.1011 + <listitem><para>A child of that changeset. Your test should 1.1012 + report this changeset as bad.</para> 1.1013 + </listitem></itemizedlist> 1.1014 + 1.1015 + </sect2> 1.1016 + <sect2> 1.1017 + <title>Beware interference between bugs</title> 1.1018 + 1.1019 + <para>It's possible that your search for one bug could be 1.1020 + disrupted by the presence of another. For example, let's say 1.1021 + your software crashes at revision 100, and worked correctly at 1.1022 + revision 50. Unknown to you, someone else introduced a 1.1023 + different crashing bug at revision 60, and fixed it at 1.1024 + revision 80. This could distort your results in one of 1.1025 + several ways.</para> 1.1026 + 1.1027 + <para>It is possible that this other bug completely 1.1028 + <quote>masks</quote> yours, which is to say that it occurs 1.1029 + before your bug has a chance to manifest itself. If you can't 1.1030 + avoid that other bug (for example, it prevents your project 1.1031 + from building), and so can't tell whether your bug is present 1.1032 + in a particular changeset, the <command role="hg-cmd">hg 1.1033 + bisect</command> command cannot help you directly. Instead, 1.1034 + you can mark a changeset as untested by running <command 1.1035 + role="hg-cmd">hg bisect --skip</command>.</para> 1.1036 + 1.1037 + <para>A different problem could arise if your test for a bug's 1.1038 + presence is not specific enough. If you check for <quote>my 1.1039 + program crashes</quote>, then both your crashing bug and an 1.1040 + unrelated crashing bug that masks it will look like the same 1.1041 + thing, and mislead <command role="hg-cmd">hg 1.1042 + bisect</command>.</para> 1.1043 + 1.1044 + <para>Another useful situation in which to use <command 1.1045 + role="hg-cmd">hg bisect --skip</command> is if you can't 1.1046 + test a revision because your project was in a broken and hence 1.1047 + untestable state at that revision, perhaps because someone 1.1048 + checked in a change that prevented the project from 1.1049 + building.</para> 1.1050 + 1.1051 + </sect2> 1.1052 + <sect2> 1.1053 + <title>Bracket your search lazily</title> 1.1054 + 1.1055 + <para>Choosing the first <quote>good</quote> and 1.1056 + <quote>bad</quote> changesets that will mark the end points of 1.1057 + your search is often easy, but it bears a little discussion 1.1058 + nevertheless. From the perspective of <command 1.1059 + role="hg-cmd">hg bisect</command>, the <quote>newest</quote> 1.1060 + changeset is conventionally <quote>bad</quote>, and the older 1.1061 + changeset is <quote>good</quote>.</para> 1.1062 + 1.1063 + <para>If you're having trouble remembering when a suitable 1.1064 + <quote>good</quote> change was, so that you can tell <command 1.1065 + role="hg-cmd">hg bisect</command>, you could do worse than 1.1066 + testing changesets at random. Just remember to eliminate 1.1067 + contenders that can't possibly exhibit the bug (perhaps 1.1068 + because the feature with the bug isn't present yet) and those 1.1069 + where another problem masks the bug (as I discussed 1.1070 + above).</para> 1.1071 + 1.1072 + <para>Even if you end up <quote>early</quote> by thousands of 1.1073 + changesets or months of history, you will only add a handful 1.1074 + of tests to the total number that <command role="hg-cmd">hg 1.1075 + bisect</command> must perform, thanks to its logarithmic 1.1076 + behaviour.</para> 1.1077 + 1.1078 + </sect2> 1.1079 + </sect1> 1.1080 +</chapter> 1.1081 + 1.1082 +<!-- 1.1083 +local variables: 1.1084 +sgml-parent-document: ("00book.xml" "book" "chapter") 1.1085 +end: 1.1086 +-->