hgbook

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