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