hgbook

annotate en/ch08-undo.xml @ 680:7226e5e750a6

Clean up chapter 8, and add content
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Apr 21 23:49:27 2009 -0700 (2009-04-21)
parents b338f5490029
children 557552d4699f
rev   line source
bos@559 1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
bos@559 2
bos@559 3 <chapter id="chap:undo">
bos@572 4 <?dbhtml filename="finding-and-fixing-mistakes.html"?>
bos@572 5 <title>Finding and fixing mistakes</title>
bos@559 6
bos@584 7 <para id="x_d2">To err might be human, but to really handle the consequences
bos@559 8 well takes a top-notch revision control system. In this chapter,
bos@559 9 we'll discuss some of the techniques you can use when you find
bos@559 10 that a problem has crept into your project. Mercurial has some
bos@559 11 highly capable features that will help you to isolate the sources
bos@559 12 of problems, and to handle them appropriately.</para>
bos@559 13
bos@559 14 <sect1>
bos@559 15 <title>Erasing local history</title>
bos@559 16
bos@559 17 <sect2>
bos@559 18 <title>The accidental commit</title>
bos@559 19
bos@584 20 <para id="x_d3">I have the occasional but persistent problem of typing
bos@559 21 rather more quickly than I can think, which sometimes results
bos@559 22 in me committing a changeset that is either incomplete or
bos@559 23 plain wrong. In my case, the usual kind of incomplete
bos@559 24 changeset is one in which I've created a new source file, but
bos@559 25 forgotten to <command role="hg-cmd">hg add</command> it. A
bos@559 26 <quote>plain wrong</quote> changeset is not as common, but no
bos@559 27 less annoying.</para>
bos@559 28
bos@559 29 </sect2>
bos@559 30 <sect2 id="sec:undo:rollback">
bos@559 31 <title>Rolling back a transaction</title>
bos@559 32
bos@592 33 <para id="x_d4">In <xref linkend="sec:concepts:txn"/>, I
bos@592 34 mentioned that Mercurial treats each modification of a
bos@592 35 repository as a <emphasis>transaction</emphasis>. Every time
bos@592 36 you commit a changeset or pull changes from another
bos@592 37 repository, Mercurial remembers what you did. You can undo,
bos@592 38 or <emphasis>roll back</emphasis>, exactly one of these
bos@592 39 actions using the <command role="hg-cmd">hg rollback</command>
bos@592 40 command. (See <xref linkend="sec:undo:rollback-after-push"/>
bos@592 41 for an important caveat about the use of this command.)</para>
bos@559 42
bos@584 43 <para id="x_d5">Here's a mistake that I often find myself making:
bos@559 44 committing a change in which I've created a new file, but
bos@567 45 forgotten to <command role="hg-cmd">hg add</command>
bos@567 46 it.</para>
bos@567 47
bos@567 48 &interaction.rollback.commit;
bos@567 49
bos@584 50 <para id="x_d6">Looking at the output of <command role="hg-cmd">hg
bos@567 51 status</command> after the commit immediately confirms the
bos@567 52 error.</para>
bos@567 53
bos@567 54 &interaction.rollback.status;
bos@567 55
bos@584 56 <para id="x_d7">The commit captured the changes to the file
bos@567 57 <filename>a</filename>, but not the new file
bos@567 58 <filename>b</filename>. If I were to push this changeset to a
bos@567 59 repository that I shared with a colleague, the chances are
bos@567 60 high that something in <filename>a</filename> would refer to
bos@567 61 <filename>b</filename>, which would not be present in their
bos@559 62 repository when they pulled my changes. I would thus become
bos@559 63 the object of some indignation.</para>
bos@559 64
bos@584 65 <para id="x_d8">However, luck is with me&emdash;I've caught my error
bos@559 66 before I pushed the changeset. I use the <command
bos@559 67 role="hg-cmd">hg rollback</command> command, and Mercurial
bos@567 68 makes that last changeset vanish.</para>
bos@567 69
bos@567 70 &interaction.rollback.rollback;
bos@567 71
bos@584 72 <para id="x_d9">Notice that the changeset is no longer present in the
bos@567 73 repository's history, and the working directory once again
bos@567 74 thinks that the file <filename>a</filename> is modified. The
bos@567 75 commit and rollback have left the working directory exactly as
bos@567 76 it was prior to the commit; the changeset has been completely
bos@567 77 erased. I can now safely <command role="hg-cmd">hg
bos@567 78 add</command> the file <filename>b</filename>, and rerun my
bos@567 79 commit.</para>
bos@567 80
bos@567 81 &interaction.rollback.add;
bos@559 82
bos@559 83 </sect2>
bos@559 84 <sect2>
bos@559 85 <title>The erroneous pull</title>
bos@559 86
bos@584 87 <para id="x_da">It's common practice with Mercurial to maintain separate
bos@559 88 development branches of a project in different repositories.
bos@559 89 Your development team might have one shared repository for
bos@559 90 your project's <quote>0.9</quote> release, and another,
bos@559 91 containing different changes, for the <quote>1.0</quote>
bos@559 92 release.</para>
bos@559 93
bos@584 94 <para id="x_db">Given this, you can imagine that the consequences could be
bos@559 95 messy if you had a local <quote>0.9</quote> repository, and
bos@559 96 accidentally pulled changes from the shared <quote>1.0</quote>
bos@559 97 repository into it. At worst, you could be paying
bos@559 98 insufficient attention, and push those changes into the shared
bos@559 99 <quote>0.9</quote> tree, confusing your entire team (but don't
bos@559 100 worry, we'll return to this horror scenario later). However,
bos@559 101 it's more likely that you'll notice immediately, because
bos@559 102 Mercurial will display the URL it's pulling from, or you will
bos@559 103 see it pull a suspiciously large number of changes into the
bos@559 104 repository.</para>
bos@559 105
bos@584 106 <para id="x_dc">The <command role="hg-cmd">hg rollback</command> command
bos@559 107 will work nicely to expunge all of the changesets that you
bos@559 108 just pulled. Mercurial groups all changes from one <command
bos@559 109 role="hg-cmd">hg pull</command> into a single transaction,
bos@559 110 so one <command role="hg-cmd">hg rollback</command> is all you
bos@559 111 need to undo this mistake.</para>
bos@559 112
bos@559 113 </sect2>
bos@559 114 <sect2 id="sec:undo:rollback-after-push">
bos@559 115 <title>Rolling back is useless once you've pushed</title>
bos@559 116
bos@584 117 <para id="x_dd">The value of the <command role="hg-cmd">hg
bos@559 118 rollback</command> command drops to zero once you've pushed
bos@559 119 your changes to another repository. Rolling back a change
bos@559 120 makes it disappear entirely, but <emphasis>only</emphasis> in
bos@559 121 the repository in which you perform the <command
bos@559 122 role="hg-cmd">hg rollback</command>. Because a rollback
bos@559 123 eliminates history, there's no way for the disappearance of a
bos@559 124 change to propagate between repositories.</para>
bos@559 125
bos@584 126 <para id="x_de">If you've pushed a change to another
bos@559 127 repository&emdash;particularly if it's a shared
bos@559 128 repository&emdash;it has essentially <quote>escaped into the
bos@559 129 wild,</quote> and you'll have to recover from your mistake
bos@680 130 in a different way. If you push a changeset somewhere, then
bos@680 131 roll it back, then pull from the repository you pushed to, the
bos@680 132 changeset you thought you'd gotten rid of will simply reappear
bos@680 133 in your repository.</para>
bos@680 134
bos@680 135 <para id="x_df">(If you absolutely know for sure that the change
bos@680 136 you want to roll back is the most recent change in the
bos@680 137 repository that you pushed to, <emphasis>and</emphasis> you
bos@680 138 know that nobody else could have pulled it from that
bos@680 139 repository, you can roll back the changeset there, too, but
bos@680 140 you really should not expect this to work reliably. Sooner or
bos@559 141 later a change really will make it into a repository that you
bos@559 142 don't directly control (or have forgotten about), and come
bos@559 143 back to bite you.)</para>
bos@559 144
bos@559 145 </sect2>
bos@559 146 <sect2>
bos@559 147 <title>You can only roll back once</title>
bos@559 148
bos@584 149 <para id="x_e0">Mercurial stores exactly one transaction in its
bos@559 150 transaction log; that transaction is the most recent one that
bos@559 151 occurred in the repository. This means that you can only roll
bos@559 152 back one transaction. If you expect to be able to roll back
bos@559 153 one transaction, then its predecessor, this is not the
bos@672 154 behavior you will get.</para>
bos@567 155
bos@567 156 &interaction.rollback.twice;
bos@567 157
bos@584 158 <para id="x_e1">Once you've rolled back one transaction in a repository,
bos@567 159 you can't roll back again in that repository until you perform
bos@559 160 another commit or pull.</para>
bos@559 161
bos@559 162 </sect2>
bos@559 163 </sect1>
bos@559 164 <sect1>
bos@559 165 <title>Reverting the mistaken change</title>
bos@559 166
bos@584 167 <para id="x_e2">If you make a modification to a file, and decide that you
bos@559 168 really didn't want to change the file at all, and you haven't
bos@559 169 yet committed your changes, the <command role="hg-cmd">hg
bos@559 170 revert</command> command is the one you'll need. It looks at
bos@559 171 the changeset that's the parent of the working directory, and
bos@559 172 restores the contents of the file to their state as of that
bos@559 173 changeset. (That's a long-winded way of saying that, in the
bos@559 174 normal case, it undoes your modifications.)</para>
bos@559 175
bos@584 176 <para id="x_e3">Let's illustrate how the <command role="hg-cmd">hg
bos@559 177 revert</command> command works with yet another small example.
bos@559 178 We'll begin by modifying a file that Mercurial is already
bos@567 179 tracking.</para>
bos@567 180
bos@567 181 &interaction.daily.revert.modify;
bos@567 182
bos@584 183 <para id="x_e4">If we don't
bos@559 184 want that change, we can simply <command role="hg-cmd">hg
bos@567 185 revert</command> the file.</para>
bos@567 186
bos@567 187 &interaction.daily.revert.unmodify;
bos@567 188
bos@584 189 <para id="x_e5">The <command role="hg-cmd">hg revert</command> command
bos@567 190 provides us with an extra degree of safety by saving our
bos@567 191 modified file with a <filename>.orig</filename>
bos@567 192 extension.</para>
bos@567 193
bos@567 194 &interaction.daily.revert.status;
bos@559 195
bos@680 196 <tip>
bos@680 197 <title>Be careful with <filename>.orig</filename> files</title>
bos@680 198
bos@680 199 <para>It's extremely unlikely that you are either using
bos@680 200 Mercurial to manage files with <filename>.orig</filename>
bos@680 201 extensions or that you even care about the contents of such
bos@680 202 files. Just in case, though, it's useful to remember that
bos@680 203 <command role="hg-cmd">hg revert</command> will
bos@680 204 unconditionally overwrite an existing file with a
bos@680 205 <filename>.orig</filename> extension. For instance, if you
bos@680 206 already have a file named <filename>foo.orig</filename> when
bos@680 207 you revert <filename>foo</filename>, the contents of
bos@680 208 <filename>foo.orig</filename> will be clobbered.</para>
bos@680 209 </tip>
bos@680 210
bos@584 211 <para id="x_e6">Here is a summary of the cases that the <command
bos@559 212 role="hg-cmd">hg revert</command> command can deal with. We
bos@559 213 will describe each of these in more detail in the section that
bos@559 214 follows.</para>
bos@559 215 <itemizedlist>
bos@584 216 <listitem><para id="x_e7">If you modify a file, it will restore the file
bos@559 217 to its unmodified state.</para>
bos@559 218 </listitem>
bos@584 219 <listitem><para id="x_e8">If you <command role="hg-cmd">hg add</command> a
bos@559 220 file, it will undo the <quote>added</quote> state of the
bos@559 221 file, but leave the file itself untouched.</para>
bos@559 222 </listitem>
bos@584 223 <listitem><para id="x_e9">If you delete a file without telling Mercurial,
bos@559 224 it will restore the file to its unmodified contents.</para>
bos@559 225 </listitem>
bos@584 226 <listitem><para id="x_ea">If you use the <command role="hg-cmd">hg
bos@559 227 remove</command> command to remove a file, it will undo
bos@559 228 the <quote>removed</quote> state of the file, and restore
bos@559 229 the file to its unmodified contents.</para>
bos@559 230 </listitem></itemizedlist>
bos@559 231
bos@559 232 <sect2 id="sec:undo:mgmt">
bos@559 233 <title>File management errors</title>
bos@559 234
bos@584 235 <para id="x_eb">The <command role="hg-cmd">hg revert</command> command is
bos@559 236 useful for more than just modified files. It lets you reverse
bos@559 237 the results of all of Mercurial's file management
bos@559 238 commands&emdash;<command role="hg-cmd">hg add</command>,
bos@559 239 <command role="hg-cmd">hg remove</command>, and so on.</para>
bos@559 240
bos@584 241 <para id="x_ec">If you <command role="hg-cmd">hg add</command> a file,
bos@559 242 then decide that in fact you don't want Mercurial to track it,
bos@559 243 use <command role="hg-cmd">hg revert</command> to undo the
bos@559 244 add. Don't worry; Mercurial will not modify the file in any
bos@567 245 way. It will just <quote>unmark</quote> the file.</para>
bos@567 246
bos@567 247 &interaction.daily.revert.add;
bos@559 248
bos@584 249 <para id="x_ed">Similarly, if you ask Mercurial to <command
bos@559 250 role="hg-cmd">hg remove</command> a file, you can use
bos@559 251 <command role="hg-cmd">hg revert</command> to restore it to
bos@559 252 the contents it had as of the parent of the working directory.
bos@567 253 &interaction.daily.revert.remove; This works just as
bos@559 254 well for a file that you deleted by hand, without telling
bos@559 255 Mercurial (recall that in Mercurial terminology, this kind of
bos@567 256 file is called <quote>missing</quote>).</para>
bos@567 257
bos@567 258 &interaction.daily.revert.missing;
bos@559 259
bos@584 260 <para id="x_ee">If you revert a <command role="hg-cmd">hg copy</command>,
bos@559 261 the copied-to file remains in your working directory
bos@559 262 afterwards, untracked. Since a copy doesn't affect the
bos@559 263 copied-from file in any way, Mercurial doesn't do anything
bos@567 264 with the copied-from file.</para>
bos@567 265
bos@567 266 &interaction.daily.revert.copy;
bos@559 267 </sect2>
bos@559 268 </sect1>
bos@680 269
bos@559 270 <sect1>
bos@559 271 <title>Dealing with committed changes</title>
bos@559 272
bos@680 273 <para id="x_f5">Consider a case where you have committed a change
bos@680 274 <emphasis>a</emphasis>, and another change
bos@680 275 <emphasis>b</emphasis> on top of it; you then realise that
bos@680 276 change <emphasis>a</emphasis> was incorrect. Mercurial lets you
bos@680 277 <quote>back out</quote> an entire changeset automatically, and
bos@680 278 building blocks that let you reverse part of a changeset by
bos@680 279 hand.</para>
bos@559 280
bos@592 281 <para id="x_f6">Before you read this section, here's something to
bos@592 282 keep in mind: the <command role="hg-cmd">hg backout</command>
bos@680 283 command undoes the effect of a change by
bos@680 284 <emphasis>adding</emphasis> to your repository's history, not by
bos@680 285 modifying or erasing it. It's the right tool to use if you're
bos@680 286 fixing bugs, but not if you're trying to undo some change that
bos@680 287 has catastrophic consequences. To deal with those, see
bos@559 288 <xref linkend="sec:undo:aaaiiieee"/>.</para>
bos@559 289
bos@559 290 <sect2>
bos@559 291 <title>Backing out a changeset</title>
bos@559 292
bos@584 293 <para id="x_f7">The <command role="hg-cmd">hg backout</command> command
bos@559 294 lets you <quote>undo</quote> the effects of an entire
bos@559 295 changeset in an automated fashion. Because Mercurial's
bos@559 296 history is immutable, this command <emphasis>does
bos@559 297 not</emphasis> get rid of the changeset you want to undo.
bos@559 298 Instead, it creates a new changeset that
bos@559 299 <emphasis>reverses</emphasis> the effect of the to-be-undone
bos@559 300 changeset.</para>
bos@559 301
bos@584 302 <para id="x_f8">The operation of the <command role="hg-cmd">hg
bos@559 303 backout</command> command is a little intricate, so let's
bos@559 304 illustrate it with some examples. First, we'll create a
bos@567 305 repository with some simple changes.</para>
bos@567 306
bos@567 307 &interaction.backout.init;
bos@559 308
bos@584 309 <para id="x_f9">The <command role="hg-cmd">hg backout</command> command
bos@559 310 takes a single changeset ID as its argument; this is the
bos@559 311 changeset to back out. Normally, <command role="hg-cmd">hg
bos@559 312 backout</command> will drop you into a text editor to write
bos@559 313 a commit message, so you can record why you're backing the
bos@559 314 change out. In this example, we provide a commit message on
bos@559 315 the command line using the <option
bos@559 316 role="hg-opt-backout">-m</option> option.</para>
bos@559 317
bos@559 318 </sect2>
bos@559 319 <sect2>
bos@559 320 <title>Backing out the tip changeset</title>
bos@559 321
bos@584 322 <para id="x_fa">We're going to start by backing out the last changeset we
bos@567 323 committed.</para>
bos@567 324
bos@567 325 &interaction.backout.simple;
bos@567 326
bos@584 327 <para id="x_fb">You can see that the second line from
bos@567 328 <filename>myfile</filename> is no longer present. Taking a
bos@567 329 look at the output of <command role="hg-cmd">hg log</command>
bos@567 330 gives us an idea of what the <command role="hg-cmd">hg
bos@567 331 backout</command> command has done.
bos@567 332 &interaction.backout.simple.log; Notice that the new changeset
bos@567 333 that <command role="hg-cmd">hg backout</command> has created
bos@567 334 is a child of the changeset we backed out. It's easier to see
bos@592 335 this in <xref linkend="fig:undo:backout"/>, which presents a
bos@592 336 graphical view of the change history. As you can see, the
bos@592 337 history is nice and linear.</para>
bos@559 338
bos@591 339 <figure id="fig:undo:backout">
bos@591 340 <title>Backing out a change using the <command
bos@591 341 role="hg-cmd">hg backout</command> command</title>
bos@591 342 <mediaobject>
bos@594 343 <imageobject><imagedata fileref="figs/undo-simple.png"/></imageobject>
bos@591 344 <textobject><phrase>XXX add text</phrase></textobject>
bos@591 345 </mediaobject>
bos@591 346 </figure>
bos@559 347
bos@559 348 </sect2>
bos@559 349 <sect2>
bos@559 350 <title>Backing out a non-tip change</title>
bos@559 351
bos@584 352 <para id="x_fd">If you want to back out a change other than the last one
bos@559 353 you committed, pass the <option
bos@559 354 role="hg-opt-backout">--merge</option> option to the
bos@567 355 <command role="hg-cmd">hg backout</command> command.</para>
bos@567 356
bos@567 357 &interaction.backout.non-tip.clone;
bos@567 358
bos@584 359 <para id="x_fe">This makes backing out any changeset a
bos@567 360 <quote>one-shot</quote> operation that's usually simple and
bos@567 361 fast.</para>
bos@567 362
bos@567 363 &interaction.backout.non-tip.backout;
bos@559 364
bos@584 365 <para id="x_ff">If you take a look at the contents of
bos@559 366 <filename>myfile</filename> after the backout finishes, you'll
bos@559 367 see that the first and third changes are present, but not the
bos@567 368 second.</para>
bos@567 369
bos@567 370 &interaction.backout.non-tip.cat;
bos@559 371
bos@592 372 <para id="x_100">As the graphical history in <xref
bos@559 373 linkend="fig:undo:backout-non-tip"/> illustrates, Mercurial
bos@680 374 still commits one change in this kind of situation (the
bos@680 375 box-shaped node is the ones that Mercurial commits
bos@680 376 automatically), but the revision graph now looks different.
bos@680 377 Before Mercurial begins the backout process, it first
bos@680 378 remembers what the current parent of the working directory is.
bos@680 379 It then backs out the target changeset, and commits that as a
bos@680 380 changeset. Finally, it merges back to the previous parent of
bos@680 381 the working directory, but notice that it <emphasis>does not
bos@680 382 commit</emphasis> the result of the merge. The repository
bos@680 383 now contains two heads, and the working directory is in a
bos@680 384 merge state.</para>
bos@559 385
bos@591 386 <figure id="fig:undo:backout-non-tip">
bos@591 387 <title>Automated backout of a non-tip change using the
bos@591 388 <command role="hg-cmd">hg backout</command> command</title>
bos@591 389 <mediaobject>
bos@594 390 <imageobject><imagedata fileref="figs/undo-non-tip.png"/></imageobject>
bos@591 391 <textobject><phrase>XXX add text</phrase></textobject>
bos@591 392 </mediaobject>
bos@591 393 </figure>
bos@559 394
bos@584 395 <para id="x_103">The result is that you end up <quote>back where you
bos@559 396 were</quote>, only with some extra history that undoes the
bos@559 397 effect of the changeset you wanted to back out.</para>
bos@559 398
bos@680 399 <para>You might wonder why Mercurial does not commit the result
bos@680 400 of the merge that it performed. The reason lies in Mercurial
bos@680 401 behaving conservatively: a merge naturally has more scope for
bos@680 402 error than simply undoing the effect of the tip changeset,
bos@680 403 so your work will be safest if you first inspect (and test!)
bos@680 404 the result of the merge, <emphasis>then</emphasis> commit
bos@680 405 it.</para>
bos@680 406
bos@559 407 <sect3>
bos@559 408 <title>Always use the <option
bos@559 409 role="hg-opt-backout">--merge</option> option</title>
bos@559 410
bos@584 411 <para id="x_104">In fact, since the <option
bos@559 412 role="hg-opt-backout">--merge</option> option will do the
bos@559 413 <quote>right thing</quote> whether or not the changeset
bos@559 414 you're backing out is the tip (i.e. it won't try to merge if
bos@559 415 it's backing out the tip, since there's no need), you should
bos@559 416 <emphasis>always</emphasis> use this option when you run the
bos@559 417 <command role="hg-cmd">hg backout</command> command.</para>
bos@559 418
bos@559 419 </sect3>
bos@559 420 </sect2>
bos@559 421 <sect2>
bos@559 422 <title>Gaining more control of the backout process</title>
bos@559 423
bos@584 424 <para id="x_105">While I've recommended that you always use the <option
bos@559 425 role="hg-opt-backout">--merge</option> option when backing
bos@559 426 out a change, the <command role="hg-cmd">hg backout</command>
bos@559 427 command lets you decide how to merge a backout changeset.
bos@559 428 Taking control of the backout process by hand is something you
bos@559 429 will rarely need to do, but it can be useful to understand
bos@559 430 what the <command role="hg-cmd">hg backout</command> command
bos@559 431 is doing for you automatically. To illustrate this, let's
bos@559 432 clone our first repository, but omit the backout change that
bos@559 433 it contains.</para>
bos@559 434
bos@567 435 &interaction.backout.manual.clone;
bos@567 436
bos@584 437 <para id="x_106">As with our
bos@559 438 earlier example, We'll commit a third changeset, then back out
bos@567 439 its parent, and see what happens.</para>
bos@567 440
bos@567 441 &interaction.backout.manual.backout;
bos@567 442
bos@584 443 <para id="x_107">Our new changeset is again a descendant of the changeset
bos@567 444 we backout out; it's thus a new head, <emphasis>not</emphasis>
bos@567 445 a descendant of the changeset that was the tip. The <command
bos@567 446 role="hg-cmd">hg backout</command> command was quite
bos@567 447 explicit in telling us this.</para>
bos@567 448
bos@567 449 &interaction.backout.manual.log;
bos@559 450
bos@584 451 <para id="x_108">Again, it's easier to see what has happened by looking at
bos@592 452 a graph of the revision history, in <xref
bos@559 453 linkend="fig:undo:backout-manual"/>. This makes it clear
bos@559 454 that when we use <command role="hg-cmd">hg backout</command>
bos@559 455 to back out a change other than the tip, Mercurial adds a new
bos@559 456 head to the repository (the change it committed is
bos@559 457 box-shaped).</para>
bos@559 458
bos@591 459 <figure id="fig:undo:backout-manual">
bos@591 460 <title>Backing out a change using the <command
bos@591 461 role="hg-cmd">hg backout</command> command</title>
bos@591 462 <mediaobject>
bos@594 463 <imageobject><imagedata fileref="figs/undo-manual.png"/></imageobject>
bos@591 464 <textobject><phrase>XXX add text</phrase></textobject>
bos@591 465 </mediaobject>
bos@591 466 </figure>
bos@559 467
bos@584 468 <para id="x_10a">After the <command role="hg-cmd">hg backout</command>
bos@559 469 command has completed, it leaves the new
bos@559 470 <quote>backout</quote> changeset as the parent of the working
bos@567 471 directory.</para>
bos@567 472
bos@567 473 &interaction.backout.manual.parents;
bos@567 474
bos@584 475 <para id="x_10b">Now we have two isolated sets of changes.</para>
bos@567 476
bos@567 477 &interaction.backout.manual.heads;
bos@559 478
bos@584 479 <para id="x_10c">Let's think about what we expect to see as the contents of
bos@559 480 <filename>myfile</filename> now. The first change should be
bos@559 481 present, because we've never backed it out. The second change
bos@559 482 should be missing, as that's the change we backed out. Since
bos@559 483 the history graph shows the third change as a separate head,
bos@559 484 we <emphasis>don't</emphasis> expect to see the third change
bos@567 485 present in <filename>myfile</filename>.</para>
bos@567 486
bos@567 487 &interaction.backout.manual.cat;
bos@567 488
bos@584 489 <para id="x_10d">To get the third change back into the file, we just do a
bos@567 490 normal merge of our two heads.</para>
bos@567 491
bos@567 492 &interaction.backout.manual.merge;
bos@567 493
bos@592 494 <para id="x_10e">Afterwards, the graphical history of our
bos@592 495 repository looks like
bos@559 496 <xref linkend="fig:undo:backout-manual-merge"/>.</para>
bos@559 497
bos@591 498 <figure id="fig:undo:backout-manual-merge">
bos@591 499 <title>Manually merging a backout change</title>
bos@591 500 <mediaobject>
bos@594 501 <imageobject><imagedata fileref="figs/undo-manual-merge.png"/></imageobject>
bos@591 502 <textobject><phrase>XXX add text</phrase></textobject>
bos@591 503 </mediaobject>
bos@591 504 </figure>
bos@559 505
bos@559 506 </sect2>
bos@559 507 <sect2>
bos@559 508 <title>Why <command role="hg-cmd">hg backout</command> works as
bos@559 509 it does</title>
bos@559 510
bos@584 511 <para id="x_110">Here's a brief description of how the <command
bos@559 512 role="hg-cmd">hg backout</command> command works.</para>
bos@559 513 <orderedlist>
bos@584 514 <listitem><para id="x_111">It ensures that the working directory is
bos@559 515 <quote>clean</quote>, i.e. that the output of <command
bos@559 516 role="hg-cmd">hg status</command> would be empty.</para>
bos@559 517 </listitem>
bos@584 518 <listitem><para id="x_112">It remembers the current parent of the working
bos@559 519 directory. Let's call this changeset
bos@680 520 <literal>orig</literal>.</para>
bos@559 521 </listitem>
bos@584 522 <listitem><para id="x_113">It does the equivalent of a <command
bos@559 523 role="hg-cmd">hg update</command> to sync the working
bos@559 524 directory to the changeset you want to back out. Let's
bos@680 525 call this changeset <literal>backout</literal>.</para>
bos@559 526 </listitem>
bos@584 527 <listitem><para id="x_114">It finds the parent of that changeset. Let's
bos@559 528 call that changeset <literal>parent</literal>.</para>
bos@559 529 </listitem>
bos@584 530 <listitem><para id="x_115">For each file that the
bos@559 531 <literal>backout</literal> changeset affected, it does the
bos@559 532 equivalent of a <command role="hg-cmd">hg revert -r
bos@559 533 parent</command> on that file, to restore it to the
bos@559 534 contents it had before that changeset was
bos@559 535 committed.</para>
bos@559 536 </listitem>
bos@584 537 <listitem><para id="x_116">It commits the result as a new changeset.
bos@559 538 This changeset has <literal>backout</literal> as its
bos@559 539 parent.</para>
bos@559 540 </listitem>
bos@584 541 <listitem><para id="x_117">If you specify <option
bos@559 542 role="hg-opt-backout">--merge</option> on the command
bos@559 543 line, it merges with <literal>orig</literal>, and commits
bos@559 544 the result of the merge.</para>
bos@559 545 </listitem></orderedlist>
bos@559 546
bos@584 547 <para id="x_118">An alternative way to implement the <command
bos@559 548 role="hg-cmd">hg backout</command> command would be to
bos@559 549 <command role="hg-cmd">hg export</command> the
bos@559 550 to-be-backed-out changeset as a diff, then use the <option
bos@559 551 role="cmd-opt-patch">--reverse</option> option to the
bos@559 552 <command>patch</command> command to reverse the effect of the
bos@559 553 change without fiddling with the working directory. This
bos@559 554 sounds much simpler, but it would not work nearly as
bos@559 555 well.</para>
bos@559 556
bos@584 557 <para id="x_119">The reason that <command role="hg-cmd">hg
bos@559 558 backout</command> does an update, a commit, a merge, and
bos@559 559 another commit is to give the merge machinery the best chance
bos@559 560 to do a good job when dealing with all the changes
bos@559 561 <emphasis>between</emphasis> the change you're backing out and
bos@559 562 the current tip.</para>
bos@559 563
bos@584 564 <para id="x_11a">If you're backing out a changeset that's 100 revisions
bos@559 565 back in your project's history, the chances that the
bos@559 566 <command>patch</command> command will be able to apply a
bos@559 567 reverse diff cleanly are not good, because intervening changes
bos@559 568 are likely to have <quote>broken the context</quote> that
bos@559 569 <command>patch</command> uses to determine whether it can
bos@559 570 apply a patch (if this sounds like gibberish, see <xref
bos@559 571 linkend="sec:mq:patch"/> for a
bos@559 572 discussion of the <command>patch</command> command). Also,
bos@559 573 Mercurial's merge machinery will handle files and directories
bos@559 574 being renamed, permission changes, and modifications to binary
bos@559 575 files, none of which <command>patch</command> can deal
bos@559 576 with.</para>
bos@559 577
bos@559 578 </sect2>
bos@559 579 </sect1>
bos@559 580 <sect1 id="sec:undo:aaaiiieee">
bos@559 581 <title>Changes that should never have been</title>
bos@559 582
bos@584 583 <para id="x_11b">Most of the time, the <command role="hg-cmd">hg
bos@559 584 backout</command> command is exactly what you need if you want
bos@559 585 to undo the effects of a change. It leaves a permanent record
bos@559 586 of exactly what you did, both when committing the original
bos@559 587 changeset and when you cleaned up after it.</para>
bos@559 588
bos@584 589 <para id="x_11c">On rare occasions, though, you may find that you've
bos@559 590 committed a change that really should not be present in the
bos@559 591 repository at all. For example, it would be very unusual, and
bos@559 592 usually considered a mistake, to commit a software project's
bos@559 593 object files as well as its source files. Object files have
bos@559 594 almost no intrinsic value, and they're <emphasis>big</emphasis>,
bos@559 595 so they increase the size of the repository and the amount of
bos@559 596 time it takes to clone or pull changes.</para>
bos@559 597
bos@584 598 <para id="x_11d">Before I discuss the options that you have if you commit a
bos@559 599 <quote>brown paper bag</quote> change (the kind that's so bad
bos@559 600 that you want to pull a brown paper bag over your head), let me
bos@559 601 first discuss some approaches that probably won't work.</para>
bos@559 602
bos@592 603 <para id="x_11e">Since Mercurial treats history as
bos@592 604 accumulative&emdash;every change builds on top of all changes
bos@592 605 that preceded it&emdash;you generally can't just make disastrous
bos@592 606 changes disappear. The one exception is when you've just
bos@592 607 committed a change, and it hasn't been pushed or pulled into
bos@592 608 another repository. That's when you can safely use the <command
bos@592 609 role="hg-cmd">hg rollback</command> command, as I detailed in
bos@592 610 <xref linkend="sec:undo:rollback"/>.</para>
bos@559 611
bos@584 612 <para id="x_11f">After you've pushed a bad change to another repository, you
bos@559 613 <emphasis>could</emphasis> still use <command role="hg-cmd">hg
bos@559 614 rollback</command> to make your local copy of the change
bos@559 615 disappear, but it won't have the consequences you want. The
bos@559 616 change will still be present in the remote repository, so it
bos@559 617 will reappear in your local repository the next time you
bos@559 618 pull.</para>
bos@559 619
bos@584 620 <para id="x_120">If a situation like this arises, and you know which
bos@559 621 repositories your bad change has propagated into, you can
bos@680 622 <emphasis>try</emphasis> to get rid of the change from
bos@559 623 <emphasis>every</emphasis> one of those repositories. This is,
bos@559 624 of course, not a satisfactory solution: if you miss even a
bos@559 625 single repository while you're expunging, the change is still
bos@559 626 <quote>in the wild</quote>, and could propagate further.</para>
bos@559 627
bos@584 628 <para id="x_121">If you've committed one or more changes
bos@559 629 <emphasis>after</emphasis> the change that you'd like to see
bos@559 630 disappear, your options are further reduced. Mercurial doesn't
bos@559 631 provide a way to <quote>punch a hole</quote> in history, leaving
bos@559 632 changesets intact.</para>
bos@559 633
bos@680 634 <sect2>
bos@680 635 <title>Backing out a merge</title>
bos@680 636
bos@680 637 <para>Since merges are often complicated, it is not unheard of
bos@680 638 for a merge to be mangled badly, but committed erroneously.
bos@680 639 Mercurial provides an important safeguard against bad merges
bos@680 640 by refusing to commit unresolved files, but human ingenuity
bos@680 641 guarantees that it is still possible to mess a merge up and
bos@680 642 commit it.</para>
bos@680 643
bos@680 644 <para>Given a bad merge that has been committed, usually the
bos@680 645 best way to approach it is to simply try to repair the damage
bos@680 646 by hand. A complete disaster that cannot be easily fixed up
bos@680 647 by hand ought to be very rare, but the <command
bos@680 648 role="hg-cmd">hg backout</command> command may help in
bos@680 649 making the cleanup easier. It offers a <option
bos@680 650 role="hg-opt-backout">--parent</option> option, which lets
bos@680 651 you specify which parent to revert to when backing out a
bos@680 652 merge.</para>
bos@680 653
bos@680 654 <figure id="fig:undo:bad-merge-1">
bos@680 655 <title>A bad merge</title>
bos@680 656 <mediaobject>
bos@680 657 <imageobject><imagedata fileref="figs/bad-merge-1.png"/></imageobject>
bos@680 658 <textobject><phrase>XXX add text</phrase></textobject>
bos@680 659 </mediaobject>
bos@680 660 </figure>
bos@680 661
bos@680 662 <para>Suppose we have a revision graph like that in <xref
bos@680 663 linkend="fig:undo:bad-merge-1"/>. What we'd like is to
bos@680 664 <emphasis>redo</emphasis> the merge of revisions 2 and
bos@680 665 3.</para>
bos@680 666
bos@680 667 <para>One way to do so would be as follows.</para>
bos@680 668
bos@680 669 <orderedlist>
bos@680 670 <listitem>
bos@680 671 <para>Call <command role="hg-cmd">hg backout --rev=4
bos@680 672 --parent=2</command>. This tells <command
bos@680 673 role="hg-cmd">hg backout</command> to back out revision
bos@680 674 4, which is the bad merge, and to when deciding which
bos@680 675 revision to prefer, to choose parent 2, one of the parents
bos@680 676 of the merge. The effect can be seen in <xref
bos@680 677 linkend="fig:undo:bad-merge-2"/>.</para>
bos@680 678 <figure id="fig:undo:bad-merge-2">
bos@680 679 <title>Backing out the merge, favoring one parent</title>
bos@680 680 <mediaobject>
bos@680 681 <imageobject><imagedata fileref="figs/bad-merge-2.png"/></imageobject>
bos@680 682 <textobject><phrase>XXX add text</phrase></textobject>
bos@680 683 </mediaobject>
bos@680 684 </figure>
bos@680 685 </listitem>
bos@680 686
bos@680 687 <listitem>
bos@680 688 <para>Call <command role="hg-cmd">hg backout --rev=4
bos@680 689 --parent=3</command>. This tells <command
bos@680 690 role="hg-cmd">hg backout</command> to back out revision
bos@680 691 4 again, but this time to choose parent 3, the other
bos@680 692 parent of the merge. The result is visible in <xref
bos@680 693 linkend="fig:undo:bad-merge-3"/>, in which the repository
bos@680 694 now contains three heads.</para>
bos@680 695 <figure id="fig:undo:bad-merge-3">
bos@680 696 <title>Backing out the merge, favoring the other
bos@680 697 parent</title>
bos@680 698 <mediaobject>
bos@680 699 <imageobject><imagedata fileref="figs/bad-merge-3.png"/></imageobject>
bos@680 700 <textobject><phrase>XXX add text</phrase></textobject>
bos@680 701 </mediaobject>
bos@680 702 </figure>
bos@680 703 </listitem>
bos@680 704
bos@680 705 <listitem>
bos@680 706 <para>Redo the bad merge by merging the two backout heads,
bos@680 707 which reduces the number of heads in the repository to
bos@680 708 two, as can be seen in <xref
bos@680 709 linkend="fig:undo:bad-merge-4"/>.</para>
bos@680 710 <figure id="fig:undo:bad-merge-4">
bos@680 711 <title>Merging the backouts</title>
bos@680 712 <mediaobject>
bos@680 713 <imageobject><imagedata fileref="figs/bad-merge-4.png"/></imageobject>
bos@680 714 <textobject><phrase>XXX add text</phrase></textobject>
bos@680 715 </mediaobject>
bos@680 716 </figure>
bos@680 717 </listitem>
bos@680 718
bos@680 719 <listitem>
bos@680 720 <para>Merge with the commit that was made after the bad
bos@680 721 merge, as shown in <xref
bos@680 722 linkend="fig:undo:bad-merge-5"/>.</para>
bos@680 723 <figure id="fig:undo:bad-merge-5">
bos@680 724 <title>Merging the backouts</title>
bos@680 725 <mediaobject>
bos@680 726 <imageobject><imagedata fileref="figs/bad-merge-5.png"/></imageobject>
bos@680 727 <textobject><phrase>XXX add text</phrase></textobject>
bos@680 728 </mediaobject>
bos@680 729 </figure>
bos@680 730 </listitem>
bos@680 731 </orderedlist>
bos@680 732 </sect2>
bos@559 733
bos@559 734 <sect2>
bos@559 735 <title>Protect yourself from <quote>escaped</quote>
bos@559 736 changes</title>
bos@559 737
bos@584 738 <para id="x_123">If you've committed some changes to your local repository
bos@559 739 and they've been pushed or pulled somewhere else, this isn't
bos@559 740 necessarily a disaster. You can protect yourself ahead of
bos@559 741 time against some classes of bad changeset. This is
bos@559 742 particularly easy if your team usually pulls changes from a
bos@559 743 central repository.</para>
bos@559 744
bos@584 745 <para id="x_124">By configuring some hooks on that repository to validate
bos@559 746 incoming changesets (see chapter <xref linkend="chap:hook"/>),
bos@559 747 you can
bos@559 748 automatically prevent some kinds of bad changeset from being
bos@559 749 pushed to the central repository at all. With such a
bos@559 750 configuration in place, some kinds of bad changeset will
bos@559 751 naturally tend to <quote>die out</quote> because they can't
bos@559 752 propagate into the central repository. Better yet, this
bos@559 753 happens without any need for explicit intervention.</para>
bos@559 754
bos@680 755 <para id="x_125">For instance, an incoming change hook that
bos@680 756 verifies that a changeset will actually compile can prevent
bos@680 757 people from inadvertently <quote>breaking the
bos@680 758 build</quote>.</para>
bos@680 759 </sect2>
bos@680 760
bos@680 761 <sect2>
bos@680 762 <title>What to do about sensitive changes that escape</title>
bos@680 763
bos@680 764 <para>Even a carefully run project can suffer an unfortunate
bos@680 765 event such as the committing and uncontrolled propagation of a
bos@680 766 file that contains important passwords.</para>
bos@680 767
bos@680 768 <para>If something like this happens to you, and the information
bos@680 769 that gets accidentally propagated is truly sensitive, your
bos@680 770 first step should be to mitigate the effect of the leak
bos@680 771 without trying to control the leak itself. If you are not 100%
bos@680 772 certain that you know exactly who could have seen the changes,
bos@680 773 you should immediately change passwords, cancel credit cards,
bos@680 774 or find some other way to make sure that the information that
bos@680 775 has leaked is no longer useful. In other words, assume that
bos@680 776 the change has propagated far and wide, and that there's
bos@680 777 nothing more you can do.</para>
bos@680 778
bos@680 779 <para>You might hope that there would be mechanisms you could
bos@680 780 use to either figure out who has seen a change or to erase the
bos@680 781 change permanently everywhere, but there are good reasons why
bos@680 782 these are not possible.</para>
bos@680 783
bos@680 784 <para>Mercurial does not provide an audit trail of who has
bos@680 785 pulled changes from a repository, because it is usually either
bos@680 786 impossible to record such information or trivial to spoof it.
bos@680 787 In a multi-user or networked environment, you should thus be
bos@680 788 extremely skeptical of yourself if you think that you have
bos@680 789 identified every place that a sensitive changeset has
bos@680 790 propagated to. Don't forget that people can and will send
bos@680 791 bundles by email, have their backup software save data
bos@680 792 offsite, carry repositories on USB sticks, and find other
bos@680 793 completely innocent ways to confound your attempts to track
bos@680 794 down every copy of a problematic change.</para>
bos@680 795
bos@680 796 <para>Mercurial also does not provide a way to make a file or
bos@680 797 changeset completely disappear from history, because there is
bos@680 798 no way to enforce its disappearance; someone could easily
bos@680 799 modify their copy of Mercurial to ignore such directives. In
bos@680 800 addition, even if Mercurial provided such a capability,
bos@680 801 someone who simply hadn't pulled a <quote>make this file
bos@680 802 disappear</quote> changeset wouldn't be affected by it, nor
bos@680 803 would web crawlers visiting at the wrong time, disk backups,
bos@680 804 or other mechanisms. Indeed, no distributed revision control
bos@680 805 system can make data reliably vanish. Providing the illusion
bos@680 806 of such control could easily give a false sense of security,
bos@680 807 and be worse than not providing it at all.</para>
bos@559 808 </sect2>
bos@559 809 </sect1>
bos@680 810
bos@559 811 <sect1 id="sec:undo:bisect">
bos@559 812 <title>Finding the source of a bug</title>
bos@559 813
bos@584 814 <para id="x_126">While it's all very well to be able to back out a changeset
bos@559 815 that introduced a bug, this requires that you know which
bos@559 816 changeset to back out. Mercurial provides an invaluable
bos@559 817 command, called <command role="hg-cmd">hg bisect</command>, that
bos@559 818 helps you to automate this process and accomplish it very
bos@559 819 efficiently.</para>
bos@559 820
bos@584 821 <para id="x_127">The idea behind the <command role="hg-cmd">hg
bos@559 822 bisect</command> command is that a changeset has introduced
bos@672 823 some change of behavior that you can identify with a simple
bos@559 824 binary test. You don't know which piece of code introduced the
bos@559 825 change, but you know how to test for the presence of the bug.
bos@559 826 The <command role="hg-cmd">hg bisect</command> command uses your
bos@559 827 test to direct its search for the changeset that introduced the
bos@559 828 code that caused the bug.</para>
bos@559 829
bos@584 830 <para id="x_128">Here are a few scenarios to help you understand how you
bos@559 831 might apply this command.</para>
bos@559 832 <itemizedlist>
bos@584 833 <listitem><para id="x_129">The most recent version of your software has a
bos@559 834 bug that you remember wasn't present a few weeks ago, but
bos@559 835 you don't know when it was introduced. Here, your binary
bos@559 836 test checks for the presence of that bug.</para>
bos@559 837 </listitem>
bos@584 838 <listitem><para id="x_12a">You fixed a bug in a rush, and now it's time to
bos@559 839 close the entry in your team's bug database. The bug
bos@559 840 database requires a changeset ID when you close an entry,
bos@559 841 but you don't remember which changeset you fixed the bug in.
bos@559 842 Once again, your binary test checks for the presence of the
bos@559 843 bug.</para>
bos@559 844 </listitem>
bos@584 845 <listitem><para id="x_12b">Your software works correctly, but runs 15%
bos@559 846 slower than the last time you measured it. You want to know
bos@559 847 which changeset introduced the performance regression. In
bos@559 848 this case, your binary test measures the performance of your
bos@559 849 software, to see whether it's <quote>fast</quote> or
bos@559 850 <quote>slow</quote>.</para>
bos@559 851 </listitem>
bos@584 852 <listitem><para id="x_12c">The sizes of the components of your project that
bos@559 853 you ship exploded recently, and you suspect that something
bos@559 854 changed in the way you build your project.</para>
bos@559 855 </listitem></itemizedlist>
bos@559 856
bos@584 857 <para id="x_12d">From these examples, it should be clear that the <command
bos@559 858 role="hg-cmd">hg bisect</command> command is not useful only
bos@559 859 for finding the sources of bugs. You can use it to find any
bos@559 860 <quote>emergent property</quote> of a repository (anything that
bos@559 861 you can't find from a simple text search of the files in the
bos@559 862 tree) for which you can write a binary test.</para>
bos@559 863
bos@584 864 <para id="x_12e">We'll introduce a little bit of terminology here, just to
bos@559 865 make it clear which parts of the search process are your
bos@559 866 responsibility, and which are Mercurial's. A
bos@559 867 <emphasis>test</emphasis> is something that
bos@559 868 <emphasis>you</emphasis> run when <command role="hg-cmd">hg
bos@559 869 bisect</command> chooses a changeset. A
bos@559 870 <emphasis>probe</emphasis> is what <command role="hg-cmd">hg
bos@559 871 bisect</command> runs to tell whether a revision is good.
bos@559 872 Finally, we'll use the word <quote>bisect</quote>, as both a
bos@559 873 noun and a verb, to stand in for the phrase <quote>search using
bos@559 874 the <command role="hg-cmd">hg bisect</command>
bos@559 875 command</quote>.</para>
bos@559 876
bos@584 877 <para id="x_12f">One simple way to automate the searching process would be
bos@559 878 simply to probe every changeset. However, this scales poorly.
bos@559 879 If it took ten minutes to test a single changeset, and you had
bos@559 880 10,000 changesets in your repository, the exhaustive approach
bos@559 881 would take on average 35 <emphasis>days</emphasis> to find the
bos@559 882 changeset that introduced a bug. Even if you knew that the bug
bos@559 883 was introduced by one of the last 500 changesets, and limited
bos@559 884 your search to those, you'd still be looking at over 40 hours to
bos@559 885 find the changeset that introduced your bug.</para>
bos@559 886
bos@584 887 <para id="x_130">What the <command role="hg-cmd">hg bisect</command> command
bos@559 888 does is use its knowledge of the <quote>shape</quote> of your
bos@559 889 project's revision history to perform a search in time
bos@559 890 proportional to the <emphasis>logarithm</emphasis> of the number
bos@559 891 of changesets to check (the kind of search it performs is called
bos@559 892 a dichotomic search). With this approach, searching through
bos@559 893 10,000 changesets will take less than three hours, even at ten
bos@559 894 minutes per test (the search will require about 14 tests).
bos@559 895 Limit your search to the last hundred changesets, and it will
bos@559 896 take only about an hour (roughly seven tests).</para>
bos@559 897
bos@584 898 <para id="x_131">The <command role="hg-cmd">hg bisect</command> command is
bos@559 899 aware of the <quote>branchy</quote> nature of a Mercurial
bos@559 900 project's revision history, so it has no problems dealing with
bos@559 901 branches, merges, or multiple heads in a repository. It can
bos@559 902 prune entire branches of history with a single probe, which is
bos@559 903 how it operates so efficiently.</para>
bos@559 904
bos@559 905 <sect2>
bos@559 906 <title>Using the <command role="hg-cmd">hg bisect</command>
bos@559 907 command</title>
bos@559 908
bos@584 909 <para id="x_132">Here's an example of <command role="hg-cmd">hg
bos@559 910 bisect</command> in action.</para>
bos@559 911
bos@559 912 <note>
bos@584 913 <para id="x_133"> In versions 0.9.5 and earlier of Mercurial, <command
bos@559 914 role="hg-cmd">hg bisect</command> was not a core command:
bos@559 915 it was distributed with Mercurial as an extension. This
bos@559 916 section describes the built-in command, not the old
bos@559 917 extension.</para>
bos@559 918 </note>
bos@559 919
bos@584 920 <para id="x_134">Now let's create a repository, so that we can try out the
bos@559 921 <command role="hg-cmd">hg bisect</command> command in
bos@567 922 isolation.</para>
bos@567 923
bos@567 924 &interaction.bisect.init;
bos@567 925
bos@584 926 <para id="x_135">We'll simulate a project that has a bug in it in a
bos@567 927 simple-minded way: create trivial changes in a loop, and
bos@567 928 nominate one specific change that will have the
bos@567 929 <quote>bug</quote>. This loop creates 35 changesets, each
bos@567 930 adding a single file to the repository. We'll represent our
bos@567 931 <quote>bug</quote> with a file that contains the text <quote>i
bos@567 932 have a gub</quote>.</para>
bos@567 933
bos@567 934 &interaction.bisect.commits;
bos@559 935
bos@584 936 <para id="x_136">The next thing that we'd like to do is figure out how to
bos@559 937 use the <command role="hg-cmd">hg bisect</command> command.
bos@559 938 We can use Mercurial's normal built-in help mechanism for
bos@567 939 this.</para>
bos@567 940
bos@567 941 &interaction.bisect.help;
bos@559 942
bos@584 943 <para id="x_137">The <command role="hg-cmd">hg bisect</command> command
bos@559 944 works in steps. Each step proceeds as follows.</para>
bos@559 945 <orderedlist>
bos@584 946 <listitem><para id="x_138">You run your binary test.</para>
bos@559 947 <itemizedlist>
bos@584 948 <listitem><para id="x_139">If the test succeeded, you tell <command
bos@559 949 role="hg-cmd">hg bisect</command> by running the
bos@680 950 <command role="hg-cmd">hg bisect --good</command>
bos@559 951 command.</para>
bos@559 952 </listitem>
bos@584 953 <listitem><para id="x_13a">If it failed, run the <command
bos@680 954 role="hg-cmd">hg bisect --bad</command>
bos@559 955 command.</para></listitem></itemizedlist>
bos@559 956 </listitem>
bos@584 957 <listitem><para id="x_13b">The command uses your information to decide
bos@559 958 which changeset to test next.</para>
bos@559 959 </listitem>
bos@584 960 <listitem><para id="x_13c">It updates the working directory to that
bos@559 961 changeset, and the process begins again.</para>
bos@559 962 </listitem></orderedlist>
bos@584 963 <para id="x_13d">The process ends when <command role="hg-cmd">hg
bos@559 964 bisect</command> identifies a unique changeset that marks
bos@559 965 the point where your test transitioned from
bos@559 966 <quote>succeeding</quote> to <quote>failing</quote>.</para>
bos@559 967
bos@584 968 <para id="x_13e">To start the search, we must run the <command
bos@567 969 role="hg-cmd">hg bisect --reset</command> command.</para>
bos@567 970
bos@567 971 &interaction.bisect.search.init;
bos@559 972
bos@584 973 <para id="x_13f">In our case, the binary test we use is simple: we check to
bos@559 974 see if any file in the repository contains the string <quote>i
bos@559 975 have a gub</quote>. If it does, this changeset contains the
bos@559 976 change that <quote>caused the bug</quote>. By convention, a
bos@559 977 changeset that has the property we're searching for is
bos@559 978 <quote>bad</quote>, while one that doesn't is
bos@559 979 <quote>good</quote>.</para>
bos@559 980
bos@584 981 <para id="x_140">Most of the time, the revision to which the working
bos@559 982 directory is synced (usually the tip) already exhibits the
bos@559 983 problem introduced by the buggy change, so we'll mark it as
bos@567 984 <quote>bad</quote>.</para>
bos@567 985
bos@567 986 &interaction.bisect.search.bad-init;
bos@559 987
bos@584 988 <para id="x_141">Our next task is to nominate a changeset that we know
bos@559 989 <emphasis>doesn't</emphasis> have the bug; the <command
bos@559 990 role="hg-cmd">hg bisect</command> command will
bos@559 991 <quote>bracket</quote> its search between the first pair of
bos@559 992 good and bad changesets. In our case, we know that revision
bos@559 993 10 didn't have the bug. (I'll have more words about choosing
bos@567 994 the first <quote>good</quote> changeset later.)</para>
bos@567 995
bos@567 996 &interaction.bisect.search.good-init;
bos@559 997
bos@584 998 <para id="x_142">Notice that this command printed some output.</para>
bos@559 999 <itemizedlist>
bos@584 1000 <listitem><para id="x_143">It told us how many changesets it must
bos@559 1001 consider before it can identify the one that introduced
bos@559 1002 the bug, and how many tests that will require.</para>
bos@559 1003 </listitem>
bos@584 1004 <listitem><para id="x_144">It updated the working directory to the next
bos@559 1005 changeset to test, and told us which changeset it's
bos@559 1006 testing.</para>
bos@559 1007 </listitem></itemizedlist>
bos@559 1008
bos@584 1009 <para id="x_145">We now run our test in the working directory. We use the
bos@559 1010 <command>grep</command> command to see if our
bos@559 1011 <quote>bad</quote> file is present in the working directory.
bos@559 1012 If it is, this revision is bad; if not, this revision is good.
bos@567 1013 &interaction.bisect.search.step1;</para>
bos@559 1014
bos@584 1015 <para id="x_146">This test looks like a perfect candidate for automation,
bos@567 1016 so let's turn it into a shell function.</para>
bos@567 1017 &interaction.bisect.search.mytest;
bos@567 1018
bos@584 1019 <para id="x_147">We can now run an entire test step with a single command,
bos@567 1020 <literal>mytest</literal>.</para>
bos@567 1021
bos@567 1022 &interaction.bisect.search.step2;
bos@567 1023
bos@584 1024 <para id="x_148">A few more invocations of our canned test step command,
bos@567 1025 and we're done.</para>
bos@567 1026
bos@567 1027 &interaction.bisect.search.rest;
bos@559 1028
bos@584 1029 <para id="x_149">Even though we had 40 changesets to search through, the
bos@559 1030 <command role="hg-cmd">hg bisect</command> command let us find
bos@559 1031 the changeset that introduced our <quote>bug</quote> with only
bos@559 1032 five tests. Because the number of tests that the <command
bos@559 1033 role="hg-cmd">hg bisect</command> command performs grows
bos@559 1034 logarithmically with the number of changesets to search, the
bos@559 1035 advantage that it has over the <quote>brute force</quote>
bos@559 1036 search approach increases with every changeset you add.</para>
bos@559 1037
bos@559 1038 </sect2>
bos@559 1039 <sect2>
bos@559 1040 <title>Cleaning up after your search</title>
bos@559 1041
bos@584 1042 <para id="x_14a">When you're finished using the <command role="hg-cmd">hg
bos@559 1043 bisect</command> command in a repository, you can use the
bos@680 1044 <command role="hg-cmd">hg bisect --reset</command> command to
bos@559 1045 drop the information it was using to drive your search. The
bos@559 1046 command doesn't use much space, so it doesn't matter if you
bos@559 1047 forget to run this command. However, <command
bos@559 1048 role="hg-cmd">hg bisect</command> won't let you start a new
bos@559 1049 search in that repository until you do a <command
bos@680 1050 role="hg-cmd">hg bisect --reset</command>.</para>
bos@567 1051
bos@567 1052 &interaction.bisect.search.reset;
bos@559 1053
bos@559 1054 </sect2>
bos@559 1055 </sect1>
bos@559 1056 <sect1>
bos@559 1057 <title>Tips for finding bugs effectively</title>
bos@559 1058
bos@559 1059 <sect2>
bos@559 1060 <title>Give consistent input</title>
bos@559 1061
bos@584 1062 <para id="x_14b">The <command role="hg-cmd">hg bisect</command> command
bos@559 1063 requires that you correctly report the result of every test
bos@559 1064 you perform. If you tell it that a test failed when it really
bos@559 1065 succeeded, it <emphasis>might</emphasis> be able to detect the
bos@559 1066 inconsistency. If it can identify an inconsistency in your
bos@559 1067 reports, it will tell you that a particular changeset is both
bos@559 1068 good and bad. However, it can't do this perfectly; it's about
bos@559 1069 as likely to report the wrong changeset as the source of the
bos@559 1070 bug.</para>
bos@559 1071
bos@559 1072 </sect2>
bos@559 1073 <sect2>
bos@559 1074 <title>Automate as much as possible</title>
bos@559 1075
bos@584 1076 <para id="x_14c">When I started using the <command role="hg-cmd">hg
bos@559 1077 bisect</command> command, I tried a few times to run my
bos@559 1078 tests by hand, on the command line. This is an approach that
bos@559 1079 I, at least, am not suited to. After a few tries, I found
bos@559 1080 that I was making enough mistakes that I was having to restart
bos@559 1081 my searches several times before finally getting correct
bos@559 1082 results.</para>
bos@559 1083
bos@584 1084 <para id="x_14d">My initial problems with driving the <command
bos@559 1085 role="hg-cmd">hg bisect</command> command by hand occurred
bos@559 1086 even with simple searches on small repositories; if the
bos@559 1087 problem you're looking for is more subtle, or the number of
bos@559 1088 tests that <command role="hg-cmd">hg bisect</command> must
bos@559 1089 perform increases, the likelihood of operator error ruining
bos@559 1090 the search is much higher. Once I started automating my
bos@559 1091 tests, I had much better results.</para>
bos@559 1092
bos@584 1093 <para id="x_14e">The key to automated testing is twofold:</para>
bos@559 1094 <itemizedlist>
bos@584 1095 <listitem><para id="x_14f">always test for the same symptom, and</para>
bos@584 1096 </listitem>
bos@584 1097 <listitem><para id="x_150">always feed consistent input to the <command
bos@559 1098 role="hg-cmd">hg bisect</command> command.</para>
bos@559 1099 </listitem></itemizedlist>
bos@584 1100 <para id="x_151">In my tutorial example above, the <command>grep</command>
bos@559 1101 command tests for the symptom, and the <literal>if</literal>
bos@559 1102 statement takes the result of this check and ensures that we
bos@559 1103 always feed the same input to the <command role="hg-cmd">hg
bos@559 1104 bisect</command> command. The <literal>mytest</literal>
bos@559 1105 function marries these together in a reproducible way, so that
bos@559 1106 every test is uniform and consistent.</para>
bos@559 1107
bos@559 1108 </sect2>
bos@559 1109 <sect2>
bos@559 1110 <title>Check your results</title>
bos@559 1111
bos@584 1112 <para id="x_152">Because the output of a <command role="hg-cmd">hg
bos@559 1113 bisect</command> search is only as good as the input you
bos@559 1114 give it, don't take the changeset it reports as the absolute
bos@559 1115 truth. A simple way to cross-check its report is to manually
bos@559 1116 run your test at each of the following changesets:</para>
bos@559 1117 <itemizedlist>
bos@584 1118 <listitem><para id="x_153">The changeset that it reports as the first bad
bos@559 1119 revision. Your test should still report this as
bos@559 1120 bad.</para>
bos@559 1121 </listitem>
bos@584 1122 <listitem><para id="x_154">The parent of that changeset (either parent,
bos@559 1123 if it's a merge). Your test should report this changeset
bos@559 1124 as good.</para>
bos@559 1125 </listitem>
bos@584 1126 <listitem><para id="x_155">A child of that changeset. Your test should
bos@559 1127 report this changeset as bad.</para>
bos@559 1128 </listitem></itemizedlist>
bos@559 1129
bos@559 1130 </sect2>
bos@559 1131 <sect2>
bos@559 1132 <title>Beware interference between bugs</title>
bos@559 1133
bos@584 1134 <para id="x_156">It's possible that your search for one bug could be
bos@559 1135 disrupted by the presence of another. For example, let's say
bos@559 1136 your software crashes at revision 100, and worked correctly at
bos@559 1137 revision 50. Unknown to you, someone else introduced a
bos@559 1138 different crashing bug at revision 60, and fixed it at
bos@559 1139 revision 80. This could distort your results in one of
bos@559 1140 several ways.</para>
bos@559 1141
bos@584 1142 <para id="x_157">It is possible that this other bug completely
bos@559 1143 <quote>masks</quote> yours, which is to say that it occurs
bos@559 1144 before your bug has a chance to manifest itself. If you can't
bos@559 1145 avoid that other bug (for example, it prevents your project
bos@559 1146 from building), and so can't tell whether your bug is present
bos@559 1147 in a particular changeset, the <command role="hg-cmd">hg
bos@559 1148 bisect</command> command cannot help you directly. Instead,
bos@559 1149 you can mark a changeset as untested by running <command
bos@559 1150 role="hg-cmd">hg bisect --skip</command>.</para>
bos@559 1151
bos@584 1152 <para id="x_158">A different problem could arise if your test for a bug's
bos@559 1153 presence is not specific enough. If you check for <quote>my
bos@559 1154 program crashes</quote>, then both your crashing bug and an
bos@559 1155 unrelated crashing bug that masks it will look like the same
bos@559 1156 thing, and mislead <command role="hg-cmd">hg
bos@559 1157 bisect</command>.</para>
bos@559 1158
bos@584 1159 <para id="x_159">Another useful situation in which to use <command
bos@559 1160 role="hg-cmd">hg bisect --skip</command> is if you can't
bos@559 1161 test a revision because your project was in a broken and hence
bos@559 1162 untestable state at that revision, perhaps because someone
bos@559 1163 checked in a change that prevented the project from
bos@559 1164 building.</para>
bos@559 1165
bos@559 1166 </sect2>
bos@559 1167 <sect2>
bos@559 1168 <title>Bracket your search lazily</title>
bos@559 1169
bos@584 1170 <para id="x_15a">Choosing the first <quote>good</quote> and
bos@559 1171 <quote>bad</quote> changesets that will mark the end points of
bos@559 1172 your search is often easy, but it bears a little discussion
bos@559 1173 nevertheless. From the perspective of <command
bos@559 1174 role="hg-cmd">hg bisect</command>, the <quote>newest</quote>
bos@559 1175 changeset is conventionally <quote>bad</quote>, and the older
bos@559 1176 changeset is <quote>good</quote>.</para>
bos@559 1177
bos@584 1178 <para id="x_15b">If you're having trouble remembering when a suitable
bos@559 1179 <quote>good</quote> change was, so that you can tell <command
bos@559 1180 role="hg-cmd">hg bisect</command>, you could do worse than
bos@559 1181 testing changesets at random. Just remember to eliminate
bos@559 1182 contenders that can't possibly exhibit the bug (perhaps
bos@559 1183 because the feature with the bug isn't present yet) and those
bos@559 1184 where another problem masks the bug (as I discussed
bos@559 1185 above).</para>
bos@559 1186
bos@584 1187 <para id="x_15c">Even if you end up <quote>early</quote> by thousands of
bos@559 1188 changesets or months of history, you will only add a handful
bos@559 1189 of tests to the total number that <command role="hg-cmd">hg
bos@559 1190 bisect</command> must perform, thanks to its logarithmic
bos@672 1191 behavior.</para>
bos@559 1192
bos@559 1193 </sect2>
bos@559 1194 </sect1>
bos@559 1195 </chapter>
bos@559 1196
bos@559 1197 <!--
bos@559 1198 local variables:
bos@559 1199 sgml-parent-document: ("00book.xml" "book" "chapter")
bos@559 1200 end:
bos@559 1201 -->