hgbook

diff en/ch08-undo.xml @ 653:6b1577ef5135

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