hgbook
diff fr/ch09-undo.xml @ 994:c05663baf56b
merge with Bryan
author | Romain PELISSE <belaran@gmail.com> |
---|---|
date | Sat Sep 12 16:01:16 2009 +0200 (2009-09-12) |
parents | acf9dc5f088d |
children | 6f8c48362758 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/fr/ch09-undo.xml Sat Sep 12 16:01:16 2009 +0200 1.3 @@ -0,0 +1,1201 @@ 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 id="x_d2">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 id="x_d3">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 id="x_d4">In <xref linkend="sec:concepts:txn"/>, I 1.37 + mentioned that Mercurial treats each modification of a 1.38 + repository as a <emphasis>transaction</emphasis>. Every time 1.39 + you commit a changeset or pull changes from another 1.40 + repository, Mercurial remembers what you did. You can undo, 1.41 + or <emphasis>roll back</emphasis>, exactly one of these 1.42 + actions using the <command role="hg-cmd">hg rollback</command> 1.43 + command. (See <xref linkend="sec:undo:rollback-after-push"/> 1.44 + for an important caveat about the use of this command.)</para> 1.45 + 1.46 + <para id="x_d5">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 id="x_d6">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 id="x_d7">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 id="x_d8">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 id="x_d9">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 id="x_da">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 id="x_db">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 id="x_dc">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 id="x_dd">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 id="x_de">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. If you push a changeset somewhere, then 1.134 + roll it back, then pull from the repository you pushed to, the 1.135 + changeset you thought you'd gotten rid of will simply reappear 1.136 + in your repository.</para> 1.137 + 1.138 + <para id="x_df">(If you absolutely know for sure that the change 1.139 + you want to roll back is the most recent change in the 1.140 + repository that you pushed to, <emphasis>and</emphasis> you 1.141 + know that nobody else could have pulled it from that 1.142 + repository, you can roll back the changeset there, too, but 1.143 + you really should not expect this to work reliably. 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 id="x_e0">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 + behavior you will get.</para> 1.158 + 1.159 + &interaction.rollback.twice; 1.160 + 1.161 + <para id="x_e1">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 id="x_e2">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 id="x_e3">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 id="x_e4">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 id="x_e5">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 + <tip> 1.200 + <title>Be careful with <filename>.orig</filename> files</title> 1.201 + 1.202 + <para id="x_6b8">It's extremely unlikely that you are either using 1.203 + Mercurial to manage files with <filename>.orig</filename> 1.204 + extensions or that you even care about the contents of such 1.205 + files. Just in case, though, it's useful to remember that 1.206 + <command role="hg-cmd">hg revert</command> will 1.207 + unconditionally overwrite an existing file with a 1.208 + <filename>.orig</filename> extension. For instance, if you 1.209 + already have a file named <filename>foo.orig</filename> when 1.210 + you revert <filename>foo</filename>, the contents of 1.211 + <filename>foo.orig</filename> will be clobbered.</para> 1.212 + </tip> 1.213 + 1.214 + <para id="x_e6">Here is a summary of the cases that the <command 1.215 + role="hg-cmd">hg revert</command> command can deal with. We 1.216 + will describe each of these in more detail in the section that 1.217 + follows.</para> 1.218 + <itemizedlist> 1.219 + <listitem><para id="x_e7">If you modify a file, it will restore the file 1.220 + to its unmodified state.</para> 1.221 + </listitem> 1.222 + <listitem><para id="x_e8">If you <command role="hg-cmd">hg add</command> a 1.223 + file, it will undo the <quote>added</quote> state of the 1.224 + file, but leave the file itself untouched.</para> 1.225 + </listitem> 1.226 + <listitem><para id="x_e9">If you delete a file without telling Mercurial, 1.227 + it will restore the file to its unmodified contents.</para> 1.228 + </listitem> 1.229 + <listitem><para id="x_ea">If you use the <command role="hg-cmd">hg 1.230 + remove</command> command to remove a file, it will undo 1.231 + the <quote>removed</quote> state of the file, and restore 1.232 + the file to its unmodified contents.</para> 1.233 + </listitem></itemizedlist> 1.234 + 1.235 + <sect2 id="sec:undo:mgmt"> 1.236 + <title>File management errors</title> 1.237 + 1.238 + <para id="x_eb">The <command role="hg-cmd">hg revert</command> command is 1.239 + useful for more than just modified files. It lets you reverse 1.240 + the results of all of Mercurial's file management 1.241 + commands&emdash;<command role="hg-cmd">hg add</command>, 1.242 + <command role="hg-cmd">hg remove</command>, and so on.</para> 1.243 + 1.244 + <para id="x_ec">If you <command role="hg-cmd">hg add</command> a file, 1.245 + then decide that in fact you don't want Mercurial to track it, 1.246 + use <command role="hg-cmd">hg revert</command> to undo the 1.247 + add. Don't worry; Mercurial will not modify the file in any 1.248 + way. It will just <quote>unmark</quote> the file.</para> 1.249 + 1.250 + &interaction.daily.revert.add; 1.251 + 1.252 + <para id="x_ed">Similarly, if you ask Mercurial to <command 1.253 + role="hg-cmd">hg remove</command> a file, you can use 1.254 + <command role="hg-cmd">hg revert</command> to restore it to 1.255 + the contents it had as of the parent of the working directory. 1.256 + &interaction.daily.revert.remove; This works just as 1.257 + well for a file that you deleted by hand, without telling 1.258 + Mercurial (recall that in Mercurial terminology, this kind of 1.259 + file is called <quote>missing</quote>).</para> 1.260 + 1.261 + &interaction.daily.revert.missing; 1.262 + 1.263 + <para id="x_ee">If you revert a <command role="hg-cmd">hg copy</command>, 1.264 + the copied-to file remains in your working directory 1.265 + afterwards, untracked. Since a copy doesn't affect the 1.266 + copied-from file in any way, Mercurial doesn't do anything 1.267 + with the copied-from file.</para> 1.268 + 1.269 + &interaction.daily.revert.copy; 1.270 + </sect2> 1.271 + </sect1> 1.272 + 1.273 + <sect1> 1.274 + <title>Dealing with committed changes</title> 1.275 + 1.276 + <para id="x_f5">Consider a case where you have committed a change 1.277 + <emphasis>a</emphasis>, and another change 1.278 + <emphasis>b</emphasis> on top of it; you then realise that 1.279 + change <emphasis>a</emphasis> was incorrect. Mercurial lets you 1.280 + <quote>back out</quote> an entire changeset automatically, and 1.281 + building blocks that let you reverse part of a changeset by 1.282 + hand.</para> 1.283 + 1.284 + <para id="x_f6">Before you read this section, here's something to 1.285 + keep in mind: the <command role="hg-cmd">hg backout</command> 1.286 + command undoes the effect of a change by 1.287 + <emphasis>adding</emphasis> to your repository's history, not by 1.288 + modifying or erasing it. It's the right tool to use if you're 1.289 + fixing bugs, but not if you're trying to undo some change that 1.290 + has catastrophic consequences. To deal with those, see 1.291 + <xref linkend="sec:undo:aaaiiieee"/>.</para> 1.292 + 1.293 + <sect2> 1.294 + <title>Backing out a changeset</title> 1.295 + 1.296 + <para id="x_f7">The <command role="hg-cmd">hg backout</command> command 1.297 + lets you <quote>undo</quote> the effects of an entire 1.298 + changeset in an automated fashion. Because Mercurial's 1.299 + history is immutable, this command <emphasis>does 1.300 + not</emphasis> get rid of the changeset you want to undo. 1.301 + Instead, it creates a new changeset that 1.302 + <emphasis>reverses</emphasis> the effect of the to-be-undone 1.303 + changeset.</para> 1.304 + 1.305 + <para id="x_f8">The operation of the <command role="hg-cmd">hg 1.306 + backout</command> command is a little intricate, so let's 1.307 + illustrate it with some examples. First, we'll create a 1.308 + repository with some simple changes.</para> 1.309 + 1.310 + &interaction.backout.init; 1.311 + 1.312 + <para id="x_f9">The <command role="hg-cmd">hg backout</command> command 1.313 + takes a single changeset ID as its argument; this is the 1.314 + changeset to back out. Normally, <command role="hg-cmd">hg 1.315 + backout</command> will drop you into a text editor to write 1.316 + a commit message, so you can record why you're backing the 1.317 + change out. In this example, we provide a commit message on 1.318 + the command line using the <option 1.319 + role="hg-opt-backout">-m</option> option.</para> 1.320 + 1.321 + </sect2> 1.322 + <sect2> 1.323 + <title>Backing out the tip changeset</title> 1.324 + 1.325 + <para id="x_fa">We're going to start by backing out the last changeset we 1.326 + committed.</para> 1.327 + 1.328 + &interaction.backout.simple; 1.329 + 1.330 + <para id="x_fb">You can see that the second line from 1.331 + <filename>myfile</filename> is no longer present. Taking a 1.332 + look at the output of <command role="hg-cmd">hg log</command> 1.333 + gives us an idea of what the <command role="hg-cmd">hg 1.334 + backout</command> command has done. 1.335 + &interaction.backout.simple.log; Notice that the new changeset 1.336 + that <command role="hg-cmd">hg backout</command> has created 1.337 + is a child of the changeset we backed out. It's easier to see 1.338 + this in <xref linkend="fig:undo:backout"/>, which presents a 1.339 + graphical view of the change history. As you can see, the 1.340 + history is nice and linear.</para> 1.341 + 1.342 + <figure id="fig:undo:backout"> 1.343 + <title>Backing out a change using the <command 1.344 + role="hg-cmd">hg backout</command> command</title> 1.345 + <mediaobject> 1.346 + <imageobject><imagedata fileref="figs/undo-simple.png"/></imageobject> 1.347 + <textobject><phrase>XXX add text</phrase></textobject> 1.348 + </mediaobject> 1.349 + </figure> 1.350 + 1.351 + </sect2> 1.352 + <sect2> 1.353 + <title>Backing out a non-tip change</title> 1.354 + 1.355 + <para id="x_fd">If you want to back out a change other than the last one 1.356 + you committed, pass the <option 1.357 + role="hg-opt-backout">--merge</option> option to the 1.358 + <command role="hg-cmd">hg backout</command> command.</para> 1.359 + 1.360 + &interaction.backout.non-tip.clone; 1.361 + 1.362 + <para id="x_fe">This makes backing out any changeset a 1.363 + <quote>one-shot</quote> operation that's usually simple and 1.364 + fast.</para> 1.365 + 1.366 + &interaction.backout.non-tip.backout; 1.367 + 1.368 + <para id="x_ff">If you take a look at the contents of 1.369 + <filename>myfile</filename> after the backout finishes, you'll 1.370 + see that the first and third changes are present, but not the 1.371 + second.</para> 1.372 + 1.373 + &interaction.backout.non-tip.cat; 1.374 + 1.375 + <para id="x_100">As the graphical history in <xref 1.376 + linkend="fig:undo:backout-non-tip"/> illustrates, Mercurial 1.377 + still commits one change in this kind of situation (the 1.378 + box-shaped node is the ones that Mercurial commits 1.379 + automatically), but the revision graph now looks different. 1.380 + Before Mercurial begins the backout process, it first 1.381 + remembers what the current parent of the working directory is. 1.382 + It then backs out the target changeset, and commits that as a 1.383 + changeset. Finally, it merges back to the previous parent of 1.384 + the working directory, but notice that it <emphasis>does not 1.385 + commit</emphasis> the result of the merge. The repository 1.386 + now contains two heads, and the working directory is in a 1.387 + merge state.</para> 1.388 + 1.389 + <figure id="fig:undo:backout-non-tip"> 1.390 + <title>Automated backout of a non-tip change using the 1.391 + <command role="hg-cmd">hg backout</command> command</title> 1.392 + <mediaobject> 1.393 + <imageobject><imagedata fileref="figs/undo-non-tip.png"/></imageobject> 1.394 + <textobject><phrase>XXX add text</phrase></textobject> 1.395 + </mediaobject> 1.396 + </figure> 1.397 + 1.398 + <para id="x_103">The result is that you end up <quote>back where you 1.399 + were</quote>, only with some extra history that undoes the 1.400 + effect of the changeset you wanted to back out.</para> 1.401 + 1.402 + <para id="x_6b9">You might wonder why Mercurial does not commit the result 1.403 + of the merge that it performed. The reason lies in Mercurial 1.404 + behaving conservatively: a merge naturally has more scope for 1.405 + error than simply undoing the effect of the tip changeset, 1.406 + so your work will be safest if you first inspect (and test!) 1.407 + the result of the merge, <emphasis>then</emphasis> commit 1.408 + it.</para> 1.409 + 1.410 + <sect3> 1.411 + <title>Always use the <option 1.412 + role="hg-opt-backout">--merge</option> option</title> 1.413 + 1.414 + <para id="x_104">In fact, since the <option 1.415 + role="hg-opt-backout">--merge</option> option will do the 1.416 + <quote>right thing</quote> whether or not the changeset 1.417 + you're backing out is the tip (i.e. it won't try to merge if 1.418 + it's backing out the tip, since there's no need), you should 1.419 + <emphasis>always</emphasis> use this option when you run the 1.420 + <command role="hg-cmd">hg backout</command> command.</para> 1.421 + 1.422 + </sect3> 1.423 + </sect2> 1.424 + <sect2> 1.425 + <title>Gaining more control of the backout process</title> 1.426 + 1.427 + <para id="x_105">While I've recommended that you always use the <option 1.428 + role="hg-opt-backout">--merge</option> option when backing 1.429 + out a change, the <command role="hg-cmd">hg backout</command> 1.430 + command lets you decide how to merge a backout changeset. 1.431 + Taking control of the backout process by hand is something you 1.432 + will rarely need to do, but it can be useful to understand 1.433 + what the <command role="hg-cmd">hg backout</command> command 1.434 + is doing for you automatically. To illustrate this, let's 1.435 + clone our first repository, but omit the backout change that 1.436 + it contains.</para> 1.437 + 1.438 + &interaction.backout.manual.clone; 1.439 + 1.440 + <para id="x_106">As with our 1.441 + earlier example, We'll commit a third changeset, then back out 1.442 + its parent, and see what happens.</para> 1.443 + 1.444 + &interaction.backout.manual.backout; 1.445 + 1.446 + <para id="x_107">Our new changeset is again a descendant of the changeset 1.447 + we backout out; it's thus a new head, <emphasis>not</emphasis> 1.448 + a descendant of the changeset that was the tip. The <command 1.449 + role="hg-cmd">hg backout</command> command was quite 1.450 + explicit in telling us this.</para> 1.451 + 1.452 + &interaction.backout.manual.log; 1.453 + 1.454 + <para id="x_108">Again, it's easier to see what has happened by looking at 1.455 + a graph of the revision history, in <xref 1.456 + linkend="fig:undo:backout-manual"/>. This makes it clear 1.457 + that when we use <command role="hg-cmd">hg backout</command> 1.458 + to back out a change other than the tip, Mercurial adds a new 1.459 + head to the repository (the change it committed is 1.460 + box-shaped).</para> 1.461 + 1.462 + <figure id="fig:undo:backout-manual"> 1.463 + <title>Backing out a change using the <command 1.464 + role="hg-cmd">hg backout</command> command</title> 1.465 + <mediaobject> 1.466 + <imageobject><imagedata fileref="figs/undo-manual.png"/></imageobject> 1.467 + <textobject><phrase>XXX add text</phrase></textobject> 1.468 + </mediaobject> 1.469 + </figure> 1.470 + 1.471 + <para id="x_10a">After the <command role="hg-cmd">hg backout</command> 1.472 + command has completed, it leaves the new 1.473 + <quote>backout</quote> changeset as the parent of the working 1.474 + directory.</para> 1.475 + 1.476 + &interaction.backout.manual.parents; 1.477 + 1.478 + <para id="x_10b">Now we have two isolated sets of changes.</para> 1.479 + 1.480 + &interaction.backout.manual.heads; 1.481 + 1.482 + <para id="x_10c">Let's think about what we expect to see as the contents of 1.483 + <filename>myfile</filename> now. The first change should be 1.484 + present, because we've never backed it out. The second change 1.485 + should be missing, as that's the change we backed out. Since 1.486 + the history graph shows the third change as a separate head, 1.487 + we <emphasis>don't</emphasis> expect to see the third change 1.488 + present in <filename>myfile</filename>.</para> 1.489 + 1.490 + &interaction.backout.manual.cat; 1.491 + 1.492 + <para id="x_10d">To get the third change back into the file, we just do a 1.493 + normal merge of our two heads.</para> 1.494 + 1.495 + &interaction.backout.manual.merge; 1.496 + 1.497 + <para id="x_10e">Afterwards, the graphical history of our 1.498 + repository looks like 1.499 + <xref linkend="fig:undo:backout-manual-merge"/>.</para> 1.500 + 1.501 + <figure id="fig:undo:backout-manual-merge"> 1.502 + <title>Manually merging a backout change</title> 1.503 + <mediaobject> 1.504 + <imageobject><imagedata fileref="figs/undo-manual-merge.png"/></imageobject> 1.505 + <textobject><phrase>XXX add text</phrase></textobject> 1.506 + </mediaobject> 1.507 + </figure> 1.508 + 1.509 + </sect2> 1.510 + <sect2> 1.511 + <title>Why <command role="hg-cmd">hg backout</command> works as 1.512 + it does</title> 1.513 + 1.514 + <para id="x_110">Here's a brief description of how the <command 1.515 + role="hg-cmd">hg backout</command> command works.</para> 1.516 + <orderedlist> 1.517 + <listitem><para id="x_111">It ensures that the working directory is 1.518 + <quote>clean</quote>, i.e. that the output of <command 1.519 + role="hg-cmd">hg status</command> would be empty.</para> 1.520 + </listitem> 1.521 + <listitem><para id="x_112">It remembers the current parent of the working 1.522 + directory. Let's call this changeset 1.523 + <literal>orig</literal>.</para> 1.524 + </listitem> 1.525 + <listitem><para id="x_113">It does the equivalent of a <command 1.526 + role="hg-cmd">hg update</command> to sync the working 1.527 + directory to the changeset you want to back out. Let's 1.528 + call this changeset <literal>backout</literal>.</para> 1.529 + </listitem> 1.530 + <listitem><para id="x_114">It finds the parent of that changeset. Let's 1.531 + call that changeset <literal>parent</literal>.</para> 1.532 + </listitem> 1.533 + <listitem><para id="x_115">For each file that the 1.534 + <literal>backout</literal> changeset affected, it does the 1.535 + equivalent of a <command role="hg-cmd">hg revert -r 1.536 + parent</command> on that file, to restore it to the 1.537 + contents it had before that changeset was 1.538 + committed.</para> 1.539 + </listitem> 1.540 + <listitem><para id="x_116">It commits the result as a new changeset. 1.541 + This changeset has <literal>backout</literal> as its 1.542 + parent.</para> 1.543 + </listitem> 1.544 + <listitem><para id="x_117">If you specify <option 1.545 + role="hg-opt-backout">--merge</option> on the command 1.546 + line, it merges with <literal>orig</literal>, and commits 1.547 + the result of the merge.</para> 1.548 + </listitem></orderedlist> 1.549 + 1.550 + <para id="x_118">An alternative way to implement the <command 1.551 + role="hg-cmd">hg backout</command> command would be to 1.552 + <command role="hg-cmd">hg export</command> the 1.553 + to-be-backed-out changeset as a diff, then use the <option 1.554 + role="cmd-opt-patch">--reverse</option> option to the 1.555 + <command>patch</command> command to reverse the effect of the 1.556 + change without fiddling with the working directory. This 1.557 + sounds much simpler, but it would not work nearly as 1.558 + well.</para> 1.559 + 1.560 + <para id="x_119">The reason that <command role="hg-cmd">hg 1.561 + backout</command> does an update, a commit, a merge, and 1.562 + another commit is to give the merge machinery the best chance 1.563 + to do a good job when dealing with all the changes 1.564 + <emphasis>between</emphasis> the change you're backing out and 1.565 + the current tip.</para> 1.566 + 1.567 + <para id="x_11a">If you're backing out a changeset that's 100 revisions 1.568 + back in your project's history, the chances that the 1.569 + <command>patch</command> command will be able to apply a 1.570 + reverse diff cleanly are not good, because intervening changes 1.571 + are likely to have <quote>broken the context</quote> that 1.572 + <command>patch</command> uses to determine whether it can 1.573 + apply a patch (if this sounds like gibberish, see <xref 1.574 + linkend="sec:mq:patch"/> for a 1.575 + discussion of the <command>patch</command> command). Also, 1.576 + Mercurial's merge machinery will handle files and directories 1.577 + being renamed, permission changes, and modifications to binary 1.578 + files, none of which <command>patch</command> can deal 1.579 + with.</para> 1.580 + 1.581 + </sect2> 1.582 + </sect1> 1.583 + <sect1 id="sec:undo:aaaiiieee"> 1.584 + <title>Changes that should never have been</title> 1.585 + 1.586 + <para id="x_11b">Most of the time, the <command role="hg-cmd">hg 1.587 + backout</command> command is exactly what you need if you want 1.588 + to undo the effects of a change. It leaves a permanent record 1.589 + of exactly what you did, both when committing the original 1.590 + changeset and when you cleaned up after it.</para> 1.591 + 1.592 + <para id="x_11c">On rare occasions, though, you may find that you've 1.593 + committed a change that really should not be present in the 1.594 + repository at all. For example, it would be very unusual, and 1.595 + usually considered a mistake, to commit a software project's 1.596 + object files as well as its source files. Object files have 1.597 + almost no intrinsic value, and they're <emphasis>big</emphasis>, 1.598 + so they increase the size of the repository and the amount of 1.599 + time it takes to clone or pull changes.</para> 1.600 + 1.601 + <para id="x_11d">Before I discuss the options that you have if you commit a 1.602 + <quote>brown paper bag</quote> change (the kind that's so bad 1.603 + that you want to pull a brown paper bag over your head), let me 1.604 + first discuss some approaches that probably won't work.</para> 1.605 + 1.606 + <para id="x_11e">Since Mercurial treats history as 1.607 + accumulative&emdash;every change builds on top of all changes 1.608 + that preceded it&emdash;you generally can't just make disastrous 1.609 + changes disappear. The one exception is when you've just 1.610 + committed a change, and it hasn't been pushed or pulled into 1.611 + another repository. That's when you can safely use the <command 1.612 + role="hg-cmd">hg rollback</command> command, as I detailed in 1.613 + <xref linkend="sec:undo:rollback"/>.</para> 1.614 + 1.615 + <para id="x_11f">After you've pushed a bad change to another repository, you 1.616 + <emphasis>could</emphasis> still use <command role="hg-cmd">hg 1.617 + rollback</command> to make your local copy of the change 1.618 + disappear, but it won't have the consequences you want. The 1.619 + change will still be present in the remote repository, so it 1.620 + will reappear in your local repository the next time you 1.621 + pull.</para> 1.622 + 1.623 + <para id="x_120">If a situation like this arises, and you know which 1.624 + repositories your bad change has propagated into, you can 1.625 + <emphasis>try</emphasis> to get rid of the change from 1.626 + <emphasis>every</emphasis> one of those repositories. This is, 1.627 + of course, not a satisfactory solution: if you miss even a 1.628 + single repository while you're expunging, the change is still 1.629 + <quote>in the wild</quote>, and could propagate further.</para> 1.630 + 1.631 + <para id="x_121">If you've committed one or more changes 1.632 + <emphasis>after</emphasis> the change that you'd like to see 1.633 + disappear, your options are further reduced. Mercurial doesn't 1.634 + provide a way to <quote>punch a hole</quote> in history, leaving 1.635 + changesets intact.</para> 1.636 + 1.637 + <sect2> 1.638 + <title>Backing out a merge</title> 1.639 + 1.640 + <para id="x_6ba">Since merges are often complicated, it is not unheard of 1.641 + for a merge to be mangled badly, but committed erroneously. 1.642 + Mercurial provides an important safeguard against bad merges 1.643 + by refusing to commit unresolved files, but human ingenuity 1.644 + guarantees that it is still possible to mess a merge up and 1.645 + commit it.</para> 1.646 + 1.647 + <para id="x_6bb">Given a bad merge that has been committed, usually the 1.648 + best way to approach it is to simply try to repair the damage 1.649 + by hand. A complete disaster that cannot be easily fixed up 1.650 + by hand ought to be very rare, but the <command 1.651 + role="hg-cmd">hg backout</command> command may help in 1.652 + making the cleanup easier. It offers a <option 1.653 + role="hg-opt-backout">--parent</option> option, which lets 1.654 + you specify which parent to revert to when backing out a 1.655 + merge.</para> 1.656 + 1.657 + <figure id="fig:undo:bad-merge-1"> 1.658 + <title>A bad merge</title> 1.659 + <mediaobject> 1.660 + <imageobject><imagedata fileref="figs/bad-merge-1.png"/></imageobject> 1.661 + <textobject><phrase>XXX add text</phrase></textobject> 1.662 + </mediaobject> 1.663 + </figure> 1.664 + 1.665 + <para id="x_6bc">Suppose we have a revision graph like that in <xref 1.666 + linkend="fig:undo:bad-merge-1"/>. What we'd like is to 1.667 + <emphasis>redo</emphasis> the merge of revisions 2 and 1.668 + 3.</para> 1.669 + 1.670 + <para id="x_6bd">One way to do so would be as follows.</para> 1.671 + 1.672 + <orderedlist> 1.673 + <listitem> 1.674 + <para id="x_6be">Call <command role="hg-cmd">hg backout --rev=4 1.675 + --parent=2</command>. This tells <command 1.676 + role="hg-cmd">hg backout</command> to back out revision 1.677 + 4, which is the bad merge, and to when deciding which 1.678 + revision to prefer, to choose parent 2, one of the parents 1.679 + of the merge. The effect can be seen in <xref 1.680 + linkend="fig:undo:bad-merge-2"/>.</para> 1.681 + <figure id="fig:undo:bad-merge-2"> 1.682 + <title>Backing out the merge, favoring one parent</title> 1.683 + <mediaobject> 1.684 + <imageobject><imagedata fileref="figs/bad-merge-2.png"/></imageobject> 1.685 + <textobject><phrase>XXX add text</phrase></textobject> 1.686 + </mediaobject> 1.687 + </figure> 1.688 + </listitem> 1.689 + 1.690 + <listitem> 1.691 + <para id="x_6bf">Call <command role="hg-cmd">hg backout --rev=4 1.692 + --parent=3</command>. This tells <command 1.693 + role="hg-cmd">hg backout</command> to back out revision 1.694 + 4 again, but this time to choose parent 3, the other 1.695 + parent of the merge. The result is visible in <xref 1.696 + linkend="fig:undo:bad-merge-3"/>, in which the repository 1.697 + now contains three heads.</para> 1.698 + <figure id="fig:undo:bad-merge-3"> 1.699 + <title>Backing out the merge, favoring the other 1.700 + parent</title> 1.701 + <mediaobject> 1.702 + <imageobject><imagedata fileref="figs/bad-merge-3.png"/></imageobject> 1.703 + <textobject><phrase>XXX add text</phrase></textobject> 1.704 + </mediaobject> 1.705 + </figure> 1.706 + </listitem> 1.707 + 1.708 + <listitem> 1.709 + <para id="x_6c0">Redo the bad merge by merging the two backout heads, 1.710 + which reduces the number of heads in the repository to 1.711 + two, as can be seen in <xref 1.712 + linkend="fig:undo:bad-merge-4"/>.</para> 1.713 + <figure id="fig:undo:bad-merge-4"> 1.714 + <title>Merging the backouts</title> 1.715 + <mediaobject> 1.716 + <imageobject><imagedata fileref="figs/bad-merge-4.png"/></imageobject> 1.717 + <textobject><phrase>XXX add text</phrase></textobject> 1.718 + </mediaobject> 1.719 + </figure> 1.720 + </listitem> 1.721 + 1.722 + <listitem> 1.723 + <para id="x_6c1">Merge with the commit that was made after the bad 1.724 + merge, as shown in <xref 1.725 + linkend="fig:undo:bad-merge-5"/>.</para> 1.726 + <figure id="fig:undo:bad-merge-5"> 1.727 + <title>Merging the backouts</title> 1.728 + <mediaobject> 1.729 + <imageobject><imagedata fileref="figs/bad-merge-5.png"/></imageobject> 1.730 + <textobject><phrase>XXX add text</phrase></textobject> 1.731 + </mediaobject> 1.732 + </figure> 1.733 + </listitem> 1.734 + </orderedlist> 1.735 + </sect2> 1.736 + 1.737 + <sect2> 1.738 + <title>Protect yourself from <quote>escaped</quote> 1.739 + changes</title> 1.740 + 1.741 + <para id="x_123">If you've committed some changes to your local repository 1.742 + and they've been pushed or pulled somewhere else, this isn't 1.743 + necessarily a disaster. You can protect yourself ahead of 1.744 + time against some classes of bad changeset. This is 1.745 + particularly easy if your team usually pulls changes from a 1.746 + central repository.</para> 1.747 + 1.748 + <para id="x_124">By configuring some hooks on that repository to validate 1.749 + incoming changesets (see chapter <xref linkend="chap:hook"/>), 1.750 + you can 1.751 + automatically prevent some kinds of bad changeset from being 1.752 + pushed to the central repository at all. With such a 1.753 + configuration in place, some kinds of bad changeset will 1.754 + naturally tend to <quote>die out</quote> because they can't 1.755 + propagate into the central repository. Better yet, this 1.756 + happens without any need for explicit intervention.</para> 1.757 + 1.758 + <para id="x_125">For instance, an incoming change hook that 1.759 + verifies that a changeset will actually compile can prevent 1.760 + people from inadvertently <quote>breaking the 1.761 + build</quote>.</para> 1.762 + </sect2> 1.763 + 1.764 + <sect2> 1.765 + <title>What to do about sensitive changes that escape</title> 1.766 + 1.767 + <para id="x_6c2">Even a carefully run project can suffer an unfortunate 1.768 + event such as the committing and uncontrolled propagation of a 1.769 + file that contains important passwords.</para> 1.770 + 1.771 + <para id="x_6c3">If something like this happens to you, and the information 1.772 + that gets accidentally propagated is truly sensitive, your 1.773 + first step should be to mitigate the effect of the leak 1.774 + without trying to control the leak itself. If you are not 100% 1.775 + certain that you know exactly who could have seen the changes, 1.776 + you should immediately change passwords, cancel credit cards, 1.777 + or find some other way to make sure that the information that 1.778 + has leaked is no longer useful. In other words, assume that 1.779 + the change has propagated far and wide, and that there's 1.780 + nothing more you can do.</para> 1.781 + 1.782 + <para id="x_6c4">You might hope that there would be mechanisms you could 1.783 + use to either figure out who has seen a change or to erase the 1.784 + change permanently everywhere, but there are good reasons why 1.785 + these are not possible.</para> 1.786 + 1.787 + <para id="x_6c5">Mercurial does not provide an audit trail of who has 1.788 + pulled changes from a repository, because it is usually either 1.789 + impossible to record such information or trivial to spoof it. 1.790 + In a multi-user or networked environment, you should thus be 1.791 + extremely skeptical of yourself if you think that you have 1.792 + identified every place that a sensitive changeset has 1.793 + propagated to. Don't forget that people can and will send 1.794 + bundles by email, have their backup software save data 1.795 + offsite, carry repositories on USB sticks, and find other 1.796 + completely innocent ways to confound your attempts to track 1.797 + down every copy of a problematic change.</para> 1.798 + 1.799 + <para id="x_6c6">Mercurial also does not provide a way to make a file or 1.800 + changeset completely disappear from history, because there is 1.801 + no way to enforce its disappearance; someone could easily 1.802 + modify their copy of Mercurial to ignore such directives. In 1.803 + addition, even if Mercurial provided such a capability, 1.804 + someone who simply hadn't pulled a <quote>make this file 1.805 + disappear</quote> changeset wouldn't be affected by it, nor 1.806 + would web crawlers visiting at the wrong time, disk backups, 1.807 + or other mechanisms. Indeed, no distributed revision control 1.808 + system can make data reliably vanish. Providing the illusion 1.809 + of such control could easily give a false sense of security, 1.810 + and be worse than not providing it at all.</para> 1.811 + </sect2> 1.812 + </sect1> 1.813 + 1.814 + <sect1 id="sec:undo:bisect"> 1.815 + <title>Finding the source of a bug</title> 1.816 + 1.817 + <para id="x_126">While it's all very well to be able to back out a changeset 1.818 + that introduced a bug, this requires that you know which 1.819 + changeset to back out. Mercurial provides an invaluable 1.820 + command, called <command role="hg-cmd">hg bisect</command>, that 1.821 + helps you to automate this process and accomplish it very 1.822 + efficiently.</para> 1.823 + 1.824 + <para id="x_127">The idea behind the <command role="hg-cmd">hg 1.825 + bisect</command> command is that a changeset has introduced 1.826 + some change of behavior that you can identify with a simple 1.827 + pass/fail test. You don't know which piece of code introduced the 1.828 + change, but you know how to test for the presence of the bug. 1.829 + The <command role="hg-cmd">hg bisect</command> command uses your 1.830 + test to direct its search for the changeset that introduced the 1.831 + code that caused the bug.</para> 1.832 + 1.833 + <para id="x_128">Here are a few scenarios to help you understand how you 1.834 + might apply this command.</para> 1.835 + <itemizedlist> 1.836 + <listitem><para id="x_129">The most recent version of your software has a 1.837 + bug that you remember wasn't present a few weeks ago, but 1.838 + you don't know when it was introduced. Here, your binary 1.839 + test checks for the presence of that bug.</para> 1.840 + </listitem> 1.841 + <listitem><para id="x_12a">You fixed a bug in a rush, and now it's time to 1.842 + close the entry in your team's bug database. The bug 1.843 + database requires a changeset ID when you close an entry, 1.844 + but you don't remember which changeset you fixed the bug in. 1.845 + Once again, your binary test checks for the presence of the 1.846 + bug.</para> 1.847 + </listitem> 1.848 + <listitem><para id="x_12b">Your software works correctly, but runs 15% 1.849 + slower than the last time you measured it. You want to know 1.850 + which changeset introduced the performance regression. In 1.851 + this case, your binary test measures the performance of your 1.852 + software, to see whether it's <quote>fast</quote> or 1.853 + <quote>slow</quote>.</para> 1.854 + </listitem> 1.855 + <listitem><para id="x_12c">The sizes of the components of your project that 1.856 + you ship exploded recently, and you suspect that something 1.857 + changed in the way you build your project.</para> 1.858 + </listitem></itemizedlist> 1.859 + 1.860 + <para id="x_12d">From these examples, it should be clear that the <command 1.861 + role="hg-cmd">hg bisect</command> command is not useful only 1.862 + for finding the sources of bugs. You can use it to find any 1.863 + <quote>emergent property</quote> of a repository (anything that 1.864 + you can't find from a simple text search of the files in the 1.865 + tree) for which you can write a binary test.</para> 1.866 + 1.867 + <para id="x_12e">We'll introduce a little bit of terminology here, just to 1.868 + make it clear which parts of the search process are your 1.869 + responsibility, and which are Mercurial's. A 1.870 + <emphasis>test</emphasis> is something that 1.871 + <emphasis>you</emphasis> run when <command role="hg-cmd">hg 1.872 + bisect</command> chooses a changeset. A 1.873 + <emphasis>probe</emphasis> is what <command role="hg-cmd">hg 1.874 + bisect</command> runs to tell whether a revision is good. 1.875 + Finally, we'll use the word <quote>bisect</quote>, as both a 1.876 + noun and a verb, to stand in for the phrase <quote>search using 1.877 + the <command role="hg-cmd">hg bisect</command> 1.878 + command</quote>.</para> 1.879 + 1.880 + <para id="x_12f">One simple way to automate the searching process would be 1.881 + simply to probe every changeset. However, this scales poorly. 1.882 + If it took ten minutes to test a single changeset, and you had 1.883 + 10,000 changesets in your repository, the exhaustive approach 1.884 + would take on average 35 <emphasis>days</emphasis> to find the 1.885 + changeset that introduced a bug. Even if you knew that the bug 1.886 + was introduced by one of the last 500 changesets, and limited 1.887 + your search to those, you'd still be looking at over 40 hours to 1.888 + find the changeset that introduced your bug.</para> 1.889 + 1.890 + <para id="x_130">What the <command role="hg-cmd">hg bisect</command> command 1.891 + does is use its knowledge of the <quote>shape</quote> of your 1.892 + project's revision history to perform a search in time 1.893 + proportional to the <emphasis>logarithm</emphasis> of the number 1.894 + of changesets to check (the kind of search it performs is called 1.895 + a dichotomic search). With this approach, searching through 1.896 + 10,000 changesets will take less than three hours, even at ten 1.897 + minutes per test (the search will require about 14 tests). 1.898 + Limit your search to the last hundred changesets, and it will 1.899 + take only about an hour (roughly seven tests).</para> 1.900 + 1.901 + <para id="x_131">The <command role="hg-cmd">hg bisect</command> command is 1.902 + aware of the <quote>branchy</quote> nature of a Mercurial 1.903 + project's revision history, so it has no problems dealing with 1.904 + branches, merges, or multiple heads in a repository. It can 1.905 + prune entire branches of history with a single probe, which is 1.906 + how it operates so efficiently.</para> 1.907 + 1.908 + <sect2> 1.909 + <title>Using the <command role="hg-cmd">hg bisect</command> 1.910 + command</title> 1.911 + 1.912 + <para id="x_132">Here's an example of <command role="hg-cmd">hg 1.913 + bisect</command> in action.</para> 1.914 + 1.915 + <note> 1.916 + <para id="x_133"> In versions 0.9.5 and earlier of Mercurial, <command 1.917 + role="hg-cmd">hg bisect</command> was not a core command: 1.918 + it was distributed with Mercurial as an extension. This 1.919 + section describes the built-in command, not the old 1.920 + extension.</para> 1.921 + </note> 1.922 + 1.923 + <para id="x_134">Now let's create a repository, so that we can try out the 1.924 + <command role="hg-cmd">hg bisect</command> command in 1.925 + isolation.</para> 1.926 + 1.927 + &interaction.bisect.init; 1.928 + 1.929 + <para id="x_135">We'll simulate a project that has a bug in it in a 1.930 + simple-minded way: create trivial changes in a loop, and 1.931 + nominate one specific change that will have the 1.932 + <quote>bug</quote>. This loop creates 35 changesets, each 1.933 + adding a single file to the repository. We'll represent our 1.934 + <quote>bug</quote> with a file that contains the text <quote>i 1.935 + have a gub</quote>.</para> 1.936 + 1.937 + &interaction.bisect.commits; 1.938 + 1.939 + <para id="x_136">The next thing that we'd like to do is figure out how to 1.940 + use the <command role="hg-cmd">hg bisect</command> command. 1.941 + We can use Mercurial's normal built-in help mechanism for 1.942 + this.</para> 1.943 + 1.944 + &interaction.bisect.help; 1.945 + 1.946 + <para id="x_137">The <command role="hg-cmd">hg bisect</command> command 1.947 + works in steps. Each step proceeds as follows.</para> 1.948 + <orderedlist> 1.949 + <listitem><para id="x_138">You run your binary test.</para> 1.950 + <itemizedlist> 1.951 + <listitem><para id="x_139">If the test succeeded, you tell <command 1.952 + role="hg-cmd">hg bisect</command> by running the 1.953 + <command role="hg-cmd">hg bisect --good</command> 1.954 + command.</para> 1.955 + </listitem> 1.956 + <listitem><para id="x_13a">If it failed, run the <command 1.957 + role="hg-cmd">hg bisect --bad</command> 1.958 + command.</para></listitem></itemizedlist> 1.959 + </listitem> 1.960 + <listitem><para id="x_13b">The command uses your information to decide 1.961 + which changeset to test next.</para> 1.962 + </listitem> 1.963 + <listitem><para id="x_13c">It updates the working directory to that 1.964 + changeset, and the process begins again.</para> 1.965 + </listitem></orderedlist> 1.966 + <para id="x_13d">The process ends when <command role="hg-cmd">hg 1.967 + bisect</command> identifies a unique changeset that marks 1.968 + the point where your test transitioned from 1.969 + <quote>succeeding</quote> to <quote>failing</quote>.</para> 1.970 + 1.971 + <para id="x_13e">To start the search, we must run the <command 1.972 + role="hg-cmd">hg bisect --reset</command> command.</para> 1.973 + 1.974 + &interaction.bisect.search.init; 1.975 + 1.976 + <para id="x_13f">In our case, the binary test we use is simple: we check to 1.977 + see if any file in the repository contains the string <quote>i 1.978 + have a gub</quote>. If it does, this changeset contains the 1.979 + change that <quote>caused the bug</quote>. By convention, a 1.980 + changeset that has the property we're searching for is 1.981 + <quote>bad</quote>, while one that doesn't is 1.982 + <quote>good</quote>.</para> 1.983 + 1.984 + <para id="x_140">Most of the time, the revision to which the working 1.985 + directory is synced (usually the tip) already exhibits the 1.986 + problem introduced by the buggy change, so we'll mark it as 1.987 + <quote>bad</quote>.</para> 1.988 + 1.989 + &interaction.bisect.search.bad-init; 1.990 + 1.991 + <para id="x_141">Our next task is to nominate a changeset that we know 1.992 + <emphasis>doesn't</emphasis> have the bug; the <command 1.993 + role="hg-cmd">hg bisect</command> command will 1.994 + <quote>bracket</quote> its search between the first pair of 1.995 + good and bad changesets. In our case, we know that revision 1.996 + 10 didn't have the bug. (I'll have more words about choosing 1.997 + the first <quote>good</quote> changeset later.)</para> 1.998 + 1.999 + &interaction.bisect.search.good-init; 1.1000 + 1.1001 + <para id="x_142">Notice that this command printed some output.</para> 1.1002 + <itemizedlist> 1.1003 + <listitem><para id="x_143">It told us how many changesets it must 1.1004 + consider before it can identify the one that introduced 1.1005 + the bug, and how many tests that will require.</para> 1.1006 + </listitem> 1.1007 + <listitem><para id="x_144">It updated the working directory to the next 1.1008 + changeset to test, and told us which changeset it's 1.1009 + testing.</para> 1.1010 + </listitem></itemizedlist> 1.1011 + 1.1012 + <para id="x_145">We now run our test in the working directory. We use the 1.1013 + <command>grep</command> command to see if our 1.1014 + <quote>bad</quote> file is present in the working directory. 1.1015 + If it is, this revision is bad; if not, this revision is good. 1.1016 + &interaction.bisect.search.step1;</para> 1.1017 + 1.1018 + <para id="x_146">This test looks like a perfect candidate for automation, 1.1019 + so let's turn it into a shell function.</para> 1.1020 + &interaction.bisect.search.mytest; 1.1021 + 1.1022 + <para id="x_147">We can now run an entire test step with a single command, 1.1023 + <literal>mytest</literal>.</para> 1.1024 + 1.1025 + &interaction.bisect.search.step2; 1.1026 + 1.1027 + <para id="x_148">A few more invocations of our canned test step command, 1.1028 + and we're done.</para> 1.1029 + 1.1030 + &interaction.bisect.search.rest; 1.1031 + 1.1032 + <para id="x_149">Even though we had 40 changesets to search through, the 1.1033 + <command role="hg-cmd">hg bisect</command> command let us find 1.1034 + the changeset that introduced our <quote>bug</quote> with only 1.1035 + five tests. Because the number of tests that the <command 1.1036 + role="hg-cmd">hg bisect</command> command performs grows 1.1037 + logarithmically with the number of changesets to search, the 1.1038 + advantage that it has over the <quote>brute force</quote> 1.1039 + search approach increases with every changeset you add.</para> 1.1040 + 1.1041 + </sect2> 1.1042 + <sect2> 1.1043 + <title>Cleaning up after your search</title> 1.1044 + 1.1045 + <para id="x_14a">When you're finished using the <command role="hg-cmd">hg 1.1046 + bisect</command> command in a repository, you can use the 1.1047 + <command role="hg-cmd">hg bisect --reset</command> command to 1.1048 + drop the information it was using to drive your search. The 1.1049 + command doesn't use much space, so it doesn't matter if you 1.1050 + forget to run this command. However, <command 1.1051 + role="hg-cmd">hg bisect</command> won't let you start a new 1.1052 + search in that repository until you do a <command 1.1053 + role="hg-cmd">hg bisect --reset</command>.</para> 1.1054 + 1.1055 + &interaction.bisect.search.reset; 1.1056 + 1.1057 + </sect2> 1.1058 + </sect1> 1.1059 + <sect1> 1.1060 + <title>Tips for finding bugs effectively</title> 1.1061 + 1.1062 + <sect2> 1.1063 + <title>Give consistent input</title> 1.1064 + 1.1065 + <para id="x_14b">The <command role="hg-cmd">hg bisect</command> command 1.1066 + requires that you correctly report the result of every test 1.1067 + you perform. If you tell it that a test failed when it really 1.1068 + succeeded, it <emphasis>might</emphasis> be able to detect the 1.1069 + inconsistency. If it can identify an inconsistency in your 1.1070 + reports, it will tell you that a particular changeset is both 1.1071 + good and bad. However, it can't do this perfectly; it's about 1.1072 + as likely to report the wrong changeset as the source of the 1.1073 + bug.</para> 1.1074 + 1.1075 + </sect2> 1.1076 + <sect2> 1.1077 + <title>Automate as much as possible</title> 1.1078 + 1.1079 + <para id="x_14c">When I started using the <command role="hg-cmd">hg 1.1080 + bisect</command> command, I tried a few times to run my 1.1081 + tests by hand, on the command line. This is an approach that 1.1082 + I, at least, am not suited to. After a few tries, I found 1.1083 + that I was making enough mistakes that I was having to restart 1.1084 + my searches several times before finally getting correct 1.1085 + results.</para> 1.1086 + 1.1087 + <para id="x_14d">My initial problems with driving the <command 1.1088 + role="hg-cmd">hg bisect</command> command by hand occurred 1.1089 + even with simple searches on small repositories; if the 1.1090 + problem you're looking for is more subtle, or the number of 1.1091 + tests that <command role="hg-cmd">hg bisect</command> must 1.1092 + perform increases, the likelihood of operator error ruining 1.1093 + the search is much higher. Once I started automating my 1.1094 + tests, I had much better results.</para> 1.1095 + 1.1096 + <para id="x_14e">The key to automated testing is twofold:</para> 1.1097 + <itemizedlist> 1.1098 + <listitem><para id="x_14f">always test for the same symptom, and</para> 1.1099 + </listitem> 1.1100 + <listitem><para id="x_150">always feed consistent input to the <command 1.1101 + role="hg-cmd">hg bisect</command> command.</para> 1.1102 + </listitem></itemizedlist> 1.1103 + <para id="x_151">In my tutorial example above, the <command>grep</command> 1.1104 + command tests for the symptom, and the <literal>if</literal> 1.1105 + statement takes the result of this check and ensures that we 1.1106 + always feed the same input to the <command role="hg-cmd">hg 1.1107 + bisect</command> command. The <literal>mytest</literal> 1.1108 + function marries these together in a reproducible way, so that 1.1109 + every test is uniform and consistent.</para> 1.1110 + 1.1111 + </sect2> 1.1112 + <sect2> 1.1113 + <title>Check your results</title> 1.1114 + 1.1115 + <para id="x_152">Because the output of a <command role="hg-cmd">hg 1.1116 + bisect</command> search is only as good as the input you 1.1117 + give it, don't take the changeset it reports as the absolute 1.1118 + truth. A simple way to cross-check its report is to manually 1.1119 + run your test at each of the following changesets:</para> 1.1120 + <itemizedlist> 1.1121 + <listitem><para id="x_153">The changeset that it reports as the first bad 1.1122 + revision. Your test should still report this as 1.1123 + bad.</para> 1.1124 + </listitem> 1.1125 + <listitem><para id="x_154">The parent of that changeset (either parent, 1.1126 + if it's a merge). Your test should report this changeset 1.1127 + as good.</para> 1.1128 + </listitem> 1.1129 + <listitem><para id="x_155">A child of that changeset. Your test should 1.1130 + report this changeset as bad.</para> 1.1131 + </listitem></itemizedlist> 1.1132 + 1.1133 + </sect2> 1.1134 + <sect2> 1.1135 + <title>Beware interference between bugs</title> 1.1136 + 1.1137 + <para id="x_156">It's possible that your search for one bug could be 1.1138 + disrupted by the presence of another. For example, let's say 1.1139 + your software crashes at revision 100, and worked correctly at 1.1140 + revision 50. Unknown to you, someone else introduced a 1.1141 + different crashing bug at revision 60, and fixed it at 1.1142 + revision 80. This could distort your results in one of 1.1143 + several ways.</para> 1.1144 + 1.1145 + <para id="x_157">It is possible that this other bug completely 1.1146 + <quote>masks</quote> yours, which is to say that it occurs 1.1147 + before your bug has a chance to manifest itself. If you can't 1.1148 + avoid that other bug (for example, it prevents your project 1.1149 + from building), and so can't tell whether your bug is present 1.1150 + in a particular changeset, the <command role="hg-cmd">hg 1.1151 + bisect</command> command cannot help you directly. Instead, 1.1152 + you can mark a changeset as untested by running <command 1.1153 + role="hg-cmd">hg bisect --skip</command>.</para> 1.1154 + 1.1155 + <para id="x_158">A different problem could arise if your test for a bug's 1.1156 + presence is not specific enough. If you check for <quote>my 1.1157 + program crashes</quote>, then both your crashing bug and an 1.1158 + unrelated crashing bug that masks it will look like the same 1.1159 + thing, and mislead <command role="hg-cmd">hg 1.1160 + bisect</command>.</para> 1.1161 + 1.1162 + <para id="x_159">Another useful situation in which to use <command 1.1163 + role="hg-cmd">hg bisect --skip</command> is if you can't 1.1164 + test a revision because your project was in a broken and hence 1.1165 + untestable state at that revision, perhaps because someone 1.1166 + checked in a change that prevented the project from 1.1167 + building.</para> 1.1168 + 1.1169 + </sect2> 1.1170 + <sect2> 1.1171 + <title>Bracket your search lazily</title> 1.1172 + 1.1173 + <para id="x_15a">Choosing the first <quote>good</quote> and 1.1174 + <quote>bad</quote> changesets that will mark the end points of 1.1175 + your search is often easy, but it bears a little discussion 1.1176 + nevertheless. From the perspective of <command 1.1177 + role="hg-cmd">hg bisect</command>, the <quote>newest</quote> 1.1178 + changeset is conventionally <quote>bad</quote>, and the older 1.1179 + changeset is <quote>good</quote>.</para> 1.1180 + 1.1181 + <para id="x_15b">If you're having trouble remembering when a suitable 1.1182 + <quote>good</quote> change was, so that you can tell <command 1.1183 + role="hg-cmd">hg bisect</command>, you could do worse than 1.1184 + testing changesets at random. Just remember to eliminate 1.1185 + contenders that can't possibly exhibit the bug (perhaps 1.1186 + because the feature with the bug isn't present yet) and those 1.1187 + where another problem masks the bug (as I discussed 1.1188 + above).</para> 1.1189 + 1.1190 + <para id="x_15c">Even if you end up <quote>early</quote> by thousands of 1.1191 + changesets or months of history, you will only add a handful 1.1192 + of tests to the total number that <command role="hg-cmd">hg 1.1193 + bisect</command> must perform, thanks to its logarithmic 1.1194 + behavior.</para> 1.1195 + 1.1196 + </sect2> 1.1197 + </sect1> 1.1198 +</chapter> 1.1199 + 1.1200 +<!-- 1.1201 +local variables: 1.1202 +sgml-parent-document: ("00book.xml" "book" "chapter") 1.1203 +end: 1.1204 +-->