--- a/web/html/backup/abcd.html Fri Feb 05 23:42:24 2010 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,929 +0,0 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 9. Finding and fixing mistakes</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="managing-releases-and-branchy-development.html" title="Chapter 8. Managing releases and branchy development"><link rel="next" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 9. Finding and fixing mistakes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="managing-releases-and-branchy-development.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="handling-repository-events-with-hooks.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:undo"><div class="titlepage"><div><div><h2 class="title">Chapter 9. Finding and fixing mistakes</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id390081">Erasing local history</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id390087">The accidental commit</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:rollback">Rolling back a transaction</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id390858">The erroneous pull</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:rollback-after-push">Rolling back is useless once you've pushed</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id391000">You can only roll back once</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id391367">Reverting the mistaken change</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:mgmt">File management errors</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id392218">Dealing with committed changes</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392287">Backing out a changeset</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392424">Backing out the tip changeset</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392766">Backing out a non-tip change</a></span></dt><dd><dl><dt><span class="sect3"><a href="finding-and-fixing-mistakes.html#id392990">Always use the --merge option</a></span></dt></dl></dd><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id393181">Gaining more control of the backout process</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id393814">Why hg backout works as
- it does</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#sec:undo:aaaiiieee">Changes that should never have been</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394303">Backing out a merge</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394612">Protect yourself from escaped
- changes</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394667">What to do about sensitive changes that escape</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#sec:undo:bisect">Finding the source of a bug</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394992">Using the hg bisect
- command</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396541">Cleaning up after your search</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id396622">Tips for finding bugs effectively</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396628">Give consistent input</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396884">Automate as much as possible</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396713">Check your results</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396770">Beware interference between bugs</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396856">Bracket your search lazily</a></span></dt></dl></dd></dl></div><p id="x_d2"><a name="x_d2"></a>To err might be human, but to really handle the consequences
- well takes a top-notch revision control system. In this chapter,
- we'll discuss some of the techniques you can use when you find
- that a problem has crept into your project. Mercurial has some
- highly capable features that will help you to isolate the sources
- of problems, and to handle them appropriately.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id390081">Erasing local history</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id390087">The accidental commit</h3></div></div></div><p id="x_d3"><a name="x_d3"></a>I have the occasional but persistent problem of typing
- rather more quickly than I can think, which sometimes results
- in me committing a changeset that is either incomplete or
- plain wrong. In my case, the usual kind of incomplete
- changeset is one in which I've created a new source file, but
- forgotten to <span class="command"><strong>hg add</strong></span> it. A
- “<span class="quote">plain wrong</span>” changeset is not as common, but no
- less annoying.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:rollback">Rolling back a transaction</h3></div></div></div><p id="x_d4"><a name="x_d4"></a>In <a class="xref" href="behind-the-scenes.html#sec:concepts:txn" title="Safe operation">the section called “Safe operation”</a>, I
- mentioned that Mercurial treats each modification of a
- repository as a <span class="emphasis"><em>transaction</em></span>. Every time
- you commit a changeset or pull changes from another
- repository, Mercurial remembers what you did. You can undo,
- or <span class="emphasis"><em>roll back</em></span>, exactly one of these
- actions using the <span class="command"><strong>hg rollback</strong></span>
-
- command. (See <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:rollback-after-push" title="Rolling back is useless once you've pushed">the section called “Rolling back is useless once you've pushed”</a>
- for an important caveat about the use of this command.)</p><p id="x_d5"><a name="x_d5"></a>Here's a mistake that I often find myself making:
- committing a change in which I've created a new file, but
- forgotten to <span class="command"><strong>hg add</strong></span>
- it.</p><pre id="id390839" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-M a
-<code class="prompt">$</code> <strong class="userinput"><code>echo b > b</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b'</code></strong>
-</pre><p id="x_d6"><a name="x_d6"></a>Looking at the output of <span class="command"><strong>hg
- status</strong></span> after the commit immediately confirms the
- error.</p><pre id="id390541" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-? b
-<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
-
-changeset: 1:f2db1de2ba4f
-tag: tip
-user: Bryan O'Sullivan <bos@serpentine.com>
-date: Tue May 05 06:55:44 2009 +0000
-summary: Add file b
-
-</pre><p id="x_d7"><a name="x_d7"></a>The commit captured the changes to the file
- <code class="filename">a</code>, but not the new file
- <code class="filename">b</code>. If I were to push this changeset to a
- repository that I shared with a colleague, the chances are
- high that something in <code class="filename">a</code> would refer to
- <code class="filename">b</code>, which would not be present in their
- repository when they pulled my changes. I would thus become
- the object of some indignation.</p><p id="x_d8"><a name="x_d8"></a>However, luck is with me—I've caught my error
- before I pushed the changeset. I use the <span class="command"><strong>hg rollback</strong></span> command, and Mercurial
- makes that last changeset vanish.</p><pre id="id391066" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
-
-rolling back last transaction
-<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
-changeset: 0:cde70bc943e1
-tag: tip
-user: Bryan O'Sullivan <bos@serpentine.com>
-date: Tue May 05 06:55:44 2009 +0000
-summary: First commit
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-M a
-? b
-</pre><p id="x_d9"><a name="x_d9"></a>Notice that the changeset is no longer present in the
- repository's history, and the working directory once again
- thinks that the file <code class="filename">a</code> is modified. The
- commit and rollback have left the working directory exactly as
- it was prior to the commit; the changeset has been completely
- erased. I can now safely <span class="command"><strong>hg
- add</strong></span> the file <code class="filename">b</code>, and rerun my
- commit.</p><pre id="id391024" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg add b</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b, this time for real'</code></strong>
-</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id390858">The erroneous pull</h3></div></div></div><p id="x_da"><a name="x_da"></a>It's common practice with Mercurial to maintain separate
- development branches of a project in different repositories.
- Your development team might have one shared repository for
- your project's “<span class="quote">0.9</span>” release, and another,
- containing different changes, for the “<span class="quote">1.0</span>”
- release.</p><p id="x_db"><a name="x_db"></a>Given this, you can imagine that the consequences could be
- messy if you had a local “<span class="quote">0.9</span>” repository, and
- accidentally pulled changes from the shared “<span class="quote">1.0</span>”
- repository into it. At worst, you could be paying
- insufficient attention, and push those changes into the shared
- “<span class="quote">0.9</span>” tree, confusing your entire team (but don't
- worry, we'll return to this horror scenario later). However,
- it's more likely that you'll notice immediately, because
- Mercurial will display the URL it's pulling from, or you will
- see it pull a suspiciously large number of changes into the
- repository.</p><p id="x_dc"><a name="x_dc"></a>The <span class="command"><strong>hg rollback</strong></span> command
- will work nicely to expunge all of the changesets that you
- just pulled. Mercurial groups all changes from one <span class="command"><strong>hg pull</strong></span> into a single transaction,
- so one <span class="command"><strong>hg rollback</strong></span> is all you
- need to undo this mistake.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:rollback-after-push">Rolling back is useless once you've pushed</h3></div></div></div><p id="x_dd"><a name="x_dd"></a>The value of the <span class="command"><strong>hg
- rollback</strong></span> command drops to zero once you've pushed
- your changes to another repository. Rolling back a change
- makes it disappear entirely, but <span class="emphasis"><em>only</em></span> in
- the repository in which you perform the <span class="command"><strong>hg rollback</strong></span>. Because a rollback
- eliminates history, there's no way for the disappearance of a
- change to propagate between repositories.</p><p id="x_de"><a name="x_de"></a>If you've pushed a change to another
- repository—particularly if it's a shared
- repository—it has essentially “<span class="quote">escaped into the
- wild,</span>” and you'll have to recover from your mistake
- in a different way. If you push a changeset somewhere, then
- roll it back, then pull from the repository you pushed to, the
- changeset you thought you'd gotten rid of will simply reappear
- in your repository.</p><p id="x_df"><a name="x_df"></a>(If you absolutely know for sure that the change
- you want to roll back is the most recent change in the
- repository that you pushed to, <span class="emphasis"><em>and</em></span> you
- know that nobody else could have pulled it from that
- repository, you can roll back the changeset there, too, but
- you really should not expect this to work reliably. Sooner or
- later a change really will make it into a repository that you
- don't directly control (or have forgotten about), and come
- back to bite you.)</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id391000">You can only roll back once</h3></div></div></div><p id="x_e0"><a name="x_e0"></a>Mercurial stores exactly one transaction in its
- transaction log; that transaction is the most recent one that
- occurred in the repository. This means that you can only roll
- back one transaction. If you expect to be able to roll back
- one transaction, then its predecessor, this is not the
- behavior you will get.</p><pre id="id391424" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
-
-rolling back last transaction
-<code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
-no rollback information available
-</pre><p id="x_e1"><a name="x_e1"></a>Once you've rolled back one transaction in a repository,
- you can't roll back again in that repository until you perform
- another commit or pull.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id391367">Reverting the mistaken change</h2></div></div></div><p id="x_e2"><a name="x_e2"></a>If you make a modification to a file, and decide that you
- really didn't want to change the file at all, and you haven't
- yet committed your changes, the <span class="command"><strong>hg
- revert</strong></span> command is the one you'll need. It looks at
- the changeset that's the parent of the working directory, and
- restores the contents of the file to their state as of that
- changeset. (That's a long-winded way of saying that, in the
- normal case, it undoes your modifications.)</p><p id="x_e3"><a name="x_e3"></a>Let's illustrate how the <span class="command"><strong>hg
- revert</strong></span> command works with yet another small example.
- We'll begin by modifying a file that Mercurial is already
- tracking.</p><pre id="id391316" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong>
-
-original content
-<code class="prompt">$</code> <strong class="userinput"><code>echo unwanted change >> file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg diff file</code></strong>
-diff -r b52afd4afc59 file
---- a/file Tue May 05 06:55:32 2009 +0000
-+++ b/file Tue May 05 06:55:32 2009 +0000
-@@ -1,1 +1,2 @@
- original content
-+unwanted change
-</pre><p id="x_e4"><a name="x_e4"></a>If we don't
- want that change, we can simply <span class="command"><strong>hg
- revert</strong></span> the file.</p><pre id="id391251" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-
-M file
-<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong>
-original content
-</pre><p id="x_e5"><a name="x_e5"></a>The <span class="command"><strong>hg revert</strong></span> command
- provides us with an extra degree of safety by saving our
- modified file with a <code class="filename">.orig</code>
- extension.</p><pre id="id391767" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-
-? file.orig
-<code class="prompt">$</code> <strong class="userinput"><code>cat file.orig</code></strong>
-original content
-unwanted change
-</pre><div class="tip"><table border="0" summary="Tip: Be careful with .orig files"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Be careful with .orig files</th></tr><tr><td align="left" valign="top"><p id="x_6b8"><a name="x_6b8"></a>It's extremely unlikely that you are either using
- Mercurial to manage files with <code class="filename">.orig</code>
- extensions or that you even care about the contents of such
- files. Just in case, though, it's useful to remember that
- <span class="command"><strong>hg revert</strong></span> will
- unconditionally overwrite an existing file with a
- <code class="filename">.orig</code> extension. For instance, if you
- already have a file named <code class="filename">foo.orig</code> when
- you revert <code class="filename">foo</code>, the contents of
- <code class="filename">foo.orig</code> will be clobbered.</p></td></tr></table></div><p id="x_e6"><a name="x_e6"></a>Here is a summary of the cases that the <span class="command"><strong>hg revert</strong></span> command can deal with. We
- will describe each of these in more detail in the section that
- follows.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_e7"><a name="x_e7"></a>If you modify a file, it will restore the file
- to its unmodified state.</p></li><li><p id="x_e8"><a name="x_e8"></a>If you <span class="command"><strong>hg add</strong></span> a
- file, it will undo the “<span class="quote">added</span>” state of the
- file, but leave the file itself untouched.</p></li><li><p id="x_e9"><a name="x_e9"></a>If you delete a file without telling Mercurial,
- it will restore the file to its unmodified contents.</p></li><li><p id="x_ea"><a name="x_ea"></a>If you use the <span class="command"><strong>hg
- remove</strong></span> command to remove a file, it will undo
- the “<span class="quote">removed</span>” state of the file, and restore
- the file to its unmodified contents.</p></li></ul></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:mgmt">File management errors</h3></div></div></div><p id="x_eb"><a name="x_eb"></a>The <span class="command"><strong>hg revert</strong></span> command is
- useful for more than just modified files. It lets you reverse
- the results of all of Mercurial's file management
- commands—<span class="command"><strong>hg add</strong></span>,
- <span class="command"><strong>hg remove</strong></span>, and so on.</p><p id="x_ec"><a name="x_ec"></a>If you <span class="command"><strong>hg add</strong></span> a file,
- then decide that in fact you don't want Mercurial to track it,
- use <span class="command"><strong>hg revert</strong></span> to undo the
- add. Don't worry; Mercurial will not modify the file in any
- way. It will just “<span class="quote">unmark</span>” the file.</p><pre id="id391756" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo oops > oops</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg add oops</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg status oops</code></strong>
-A oops
-<code class="prompt">$</code> <strong class="userinput"><code>hg revert oops</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-
-? oops
-</pre><p id="x_ed"><a name="x_ed"></a>Similarly, if you ask Mercurial to <span class="command"><strong>hg remove</strong></span> a file, you can use
- <span class="command"><strong>hg revert</strong></span> to restore it to
- the contents it had as of the parent of the working directory.
-
-</p><pre id="id392036" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg remove file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-R file
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong>
-file
-</pre><p>
-
- This works just as
- well for a file that you deleted by hand, without telling
- Mercurial (recall that in Mercurial terminology, this kind of
- file is called “<span class="quote">missing</span>”).</p><pre id="id391954" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>rm file</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-! file
-<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong>
-file
-</pre><p id="x_ee"><a name="x_ee"></a>If you revert a <span class="command"><strong>hg copy</strong></span>,
- the copied-to file remains in your working directory
- afterwards, untracked. Since a copy doesn't affect the
- copied-from file in any way, Mercurial doesn't do anything
- with the copied-from file.</p><pre id="id392181" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg copy file new-file</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg revert new-file</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
-? new-file
-</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id392218">Dealing with committed changes</h2></div></div></div><p id="x_f5"><a name="x_f5"></a>Consider a case where you have committed a change
- <span class="emphasis"><em>a</em></span>, and another change
- <span class="emphasis"><em>b</em></span> on top of it; you then realise that
- change <span class="emphasis"><em>a</em></span> was incorrect. Mercurial lets you
- “<span class="quote">back out</span>” an entire changeset automatically, and
- building blocks that let you reverse part of a changeset by
- hand.</p><p id="x_f6"><a name="x_f6"></a>Before you read this section, here's something to
- keep in mind: the <span class="command"><strong>hg backout</strong></span>
-
- command undoes the effect of a change by
- <span class="emphasis"><em>adding</em></span> to your repository's history, not by
- modifying or erasing it. It's the right tool to use if you're
- fixing bugs, but not if you're trying to undo some change that
- has catastrophic consequences. To deal with those, see
- <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:aaaiiieee" title="Changes that should never have been">the section called “Changes that should never have been”</a>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392287">Backing out a changeset</h3></div></div></div><p id="x_f7"><a name="x_f7"></a>The <span class="command"><strong>hg backout</strong></span> command
- lets you “<span class="quote">undo</span>” the effects of an entire
- changeset in an automated fashion. Because Mercurial's
- history is immutable, this command <span class="emphasis"><em>does
- not</em></span> get rid of the changeset you want to undo.
- Instead, it creates a new changeset that
- <span class="emphasis"><em>reverses</em></span> the effect of the to-be-undone
- changeset.</p><p id="x_f8"><a name="x_f8"></a>The operation of the <span class="command"><strong>hg
- backout</strong></span> command is a little intricate, so let's
- illustrate it with some examples. First, we'll create a
- repository with some simple changes.</p><pre id="id392685" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init myrepo</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>cd myrepo</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>echo first change >> myfile</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg add myfile</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'first change'</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>echo second change >> myfile</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'second change'</code></strong>
-</pre><p id="x_f9"><a name="x_f9"></a>The <span class="command"><strong>hg backout</strong></span> command
- takes a single changeset ID as its argument; this is the
- changeset to back out. Normally, <span class="command"><strong>hg
- backout</strong></span> will drop you into a text editor to write
- a commit message, so you can record why you're backing the
- change out. In this example, we provide a commit message on
- the command line using the <code class="option">-m</code> option.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392424">Backing out the tip changeset</h3></div></div></div><p id="x_fa"><a name="x_fa"></a>We're going to start by backing out the last changeset we
- committed.</p><pre id="id392577" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg backout -m 'back out second change' tip</code></strong>
-
-reverting myfile
-changeset 2:01adc4672142 backs out changeset 1:7e341ee3be7a
-<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
-first change
-</pre><p id="x_fb"><a name="x_fb"></a>You can see that the second line from
- <code class="filename">myfile</code> is no longer present. Taking a
- look at the output of <span class="command"><strong>hg log</strong></span>
- gives us an idea of what the <span class="command"><strong>hg
- backout</strong></span> command has done.
-
-
-</p><pre id="id392554" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong>
-2[tip] 01adc4672142 2009-05-05 06:55 +0000 bos
- back out second change
-
-1 7e341ee3be7a 2009-05-05 06:55 +0000 bos
- second change
-
-0 56b97fc928f2 2009-05-05 06:55 +0000 bos
- first change
-
-</pre><p>
-
- Notice that the new changeset
- that <span class="command"><strong>hg backout</strong></span> has created
- is a child of the changeset we backed out. It's easier to see
- this in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout" title="Figure 9.1. Backing out a change using the hg backout command">Figure 9.1, “Backing out a change using the hg backout command”</a>, which presents a
- graphical view of the change history. As you can see, the
- history is nice and linear.</p><div class="figure"><a name="fig:undo:backout"></a><p class="title"><b>Figure 9.1. Backing out a change using the <span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-simple.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392766">Backing out a non-tip change</h3></div></div></div><p id="x_fd"><a name="x_fd"></a>If you want to back out a change other than the last one
- you committed, pass the <code class="option">--merge</code> option to the
- <span class="command"><strong>hg backout</strong></span> command.</p><pre id="id393141" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo non-tip-repo</code></strong>
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 2 changesets with 2 changes to 1 files
-updating working directory
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-<code class="prompt">$</code> <strong class="userinput"><code>cd non-tip-repo</code></strong>
-</pre><p id="x_fe"><a name="x_fe"></a>This makes backing out any changeset a
- “<span class="quote">one-shot</span>” operation that's usually simple and
- fast.</p><pre id="id392845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo third change >> myfile</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg backout --merge -m 'back out second change' 1</code></strong>
-reverting myfile
-created new head
-changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a
-merging with changeset 3:abc7fd860049
-merging myfile
-0 files updated, 1 files merged, 0 files removed, 0 files unresolved
-(branch merge, don't forget to commit)
-</pre><p id="x_ff"><a name="x_ff"></a>If you take a look at the contents of
- <code class="filename">myfile</code> after the backout finishes, you'll
- see that the first and third changes are present, but not the
- second.</p><pre id="id392886" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
-
-first change
-third change
-</pre><p id="x_100"><a name="x_100"></a>As the graphical history in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-non-tip" title="Figure 9.2. Automated backout of a non-tip change using the hg backout command">Figure 9.2, “Automated backout of a non-tip change using the
- hg backout command”</a> illustrates, Mercurial
- still commits one change in this kind of situation (the
- box-shaped node is the ones that Mercurial commits
- automatically), but the revision graph now looks different.
- Before Mercurial begins the backout process, it first
- remembers what the current parent of the working directory is.
- It then backs out the target changeset, and commits that as a
- changeset. Finally, it merges back to the previous parent of
- the working directory, but notice that it <span class="emphasis"><em>does not
- commit</em></span> the result of the merge. The repository
- now contains two heads, and the working directory is in a
- merge state.</p><div class="figure"><a name="fig:undo:backout-non-tip"></a><p class="title"><b>Figure 9.2. Automated backout of a non-tip change using the
- <span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-non-tip.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_103"><a name="x_103"></a>The result is that you end up “<span class="quote">back where you
- were</span>”, only with some extra history that undoes the
- effect of the changeset you wanted to back out.</p><p id="x_6b9"><a name="x_6b9"></a>You might wonder why Mercurial does not commit the result
- of the merge that it performed. The reason lies in Mercurial
- behaving conservatively: a merge naturally has more scope for
- error than simply undoing the effect of the tip changeset,
- so your work will be safest if you first inspect (and test!)
- the result of the merge, <span class="emphasis"><em>then</em></span> commit
- it.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id392990">Always use the <code class="option">--merge</code> option</h4></div></div></div><p id="x_104"><a name="x_104"></a>In fact, since the <code class="option">--merge</code> option will do the
- “<span class="quote">right thing</span>” whether or not the changeset
- you're backing out is the tip (i.e. it won't try to merge if
- it's backing out the tip, since there's no need), you should
- <span class="emphasis"><em>always</em></span> use this option when you run the
- <span class="command"><strong>hg backout</strong></span> command.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id393181">Gaining more control of the backout process</h3></div></div></div><p id="x_105"><a name="x_105"></a>While I've recommended that you always use the <code class="option">--merge</code> option when backing
- out a change, the <span class="command"><strong>hg backout</strong></span>
-
- command lets you decide how to merge a backout changeset.
- Taking control of the backout process by hand is something you
- will rarely need to do, but it can be useful to understand
- what the <span class="command"><strong>hg backout</strong></span> command
- is doing for you automatically. To illustrate this, let's
- clone our first repository, but omit the backout change that
- it contains.</p><pre id="id393568" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo newrepo</code></strong>
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 2 changesets with 2 changes to 1 files
-updating working directory
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-<code class="prompt">$</code> <strong class="userinput"><code>cd newrepo</code></strong>
-
-</pre><p id="x_106"><a name="x_106"></a>As with our
- earlier example, We'll commit a third changeset, then back out
- its parent, and see what happens.</p><pre id="id393553" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo third change >> myfile</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>hg backout -m 'back out second change' 1</code></strong>
-reverting myfile
-created new head
-changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a
-the backout changeset is a new head - do not forget to merge
-(use "backout --merge" if you want to auto-merge)
-</pre><p id="x_107"><a name="x_107"></a>Our new changeset is again a descendant of the changeset
- we backout out; it's thus a new head, <span class="emphasis"><em>not</em></span>
-
- a descendant of the changeset that was the tip. The <span class="command"><strong>hg backout</strong></span> command was quite
- explicit in telling us this.</p><pre id="id393314" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong>
-3[tip]:1 abc7fd860049 2009-05-05 06:55 +0000 bos
- back out second change
-
-2 bae4005ddac4 2009-05-05 06:55 +0000 bos
- third change
-
-1 7e341ee3be7a 2009-05-05 06:55 +0000 bos
- second change
-
-0 56b97fc928f2 2009-05-05 06:55 +0000 bos
- first change
-
-</pre><p id="x_108"><a name="x_108"></a>Again, it's easier to see what has happened by looking at
- a graph of the revision history, in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-manual" title="Figure 9.3. Backing out a change using the hg backout command">Figure 9.3, “Backing out a change using the hg backout command”</a>. This makes it clear
- that when we use <span class="command"><strong>hg backout</strong></span>
- to back out a change other than the tip, Mercurial adds a new
- head to the repository (the change it committed is
- box-shaped).</p><div class="figure"><a name="fig:undo:backout-manual"></a><p class="title"><b>Figure 9.3. Backing out a change using the <span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-manual.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_10a"><a name="x_10a"></a>After the <span class="command"><strong>hg backout</strong></span>
-
- command has completed, it leaves the new
- “<span class="quote">backout</span>” changeset as the parent of the working
- directory.</p><pre id="id393912" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
-changeset: 2:bae4005ddac4
-user: Bryan O'Sullivan <bos@serpentine.com>
-date: Tue May 05 06:55:12 2009 +0000
-summary: third change
-
-</pre><p id="x_10b"><a name="x_10b"></a>Now we have two isolated sets of changes.</p><pre id="id393905" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg heads</code></strong>
-
-changeset: 3:abc7fd860049
-tag: tip
-parent: 1:7e341ee3be7a
-user: Bryan O'Sullivan <bos@serpentine.com>
-date: Tue May 05 06:55:12 2009 +0000
-summary: back out second change
-
-changeset: 2:bae4005ddac4
-user: Bryan O'Sullivan <bos@serpentine.com>
-date: Tue May 05 06:55:12 2009 +0000
-summary: third change
-
-</pre><p id="x_10c"><a name="x_10c"></a>Let's think about what we expect to see as the contents of
- <code class="filename">myfile</code> now. The first change should be
- present, because we've never backed it out. The second change
- should be missing, as that's the change we backed out. Since
- the history graph shows the third change as a separate head,
- we <span class="emphasis"><em>don't</em></span> expect to see the third change
- present in <code class="filename">myfile</code>.</p><pre id="id393884" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
-
-first change
-</pre><p id="x_10d"><a name="x_10d"></a>To get the third change back into the file, we just do a
- normal merge of our two heads.</p><pre id="id393845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
-abort: outstanding uncommitted changes
-<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'merged backout with previous tip'</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
-first change
-</pre><p id="x_10e"><a name="x_10e"></a>Afterwards, the graphical history of our
- repository looks like
- <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-manual-merge" title="Figure 9.4. Manually merging a backout change">Figure 9.4, “Manually merging a backout change”</a>.</p><div class="figure"><a name="fig:undo:backout-manual-merge"></a><p class="title"><b>Figure 9.4. Manually merging a backout change</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-manual-merge.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id393814">Why <span class="command"><strong>hg backout</strong></span> works as
- it does</h3></div></div></div><p id="x_110"><a name="x_110"></a>Here's a brief description of how the <span class="command"><strong>hg backout</strong></span> command works.</p><div class="orderedlist"><ol type="1"><li><p id="x_111"><a name="x_111"></a>It ensures that the working directory is
- “<span class="quote">clean</span>”, i.e. that the output of <span class="command"><strong>hg status</strong></span> would be empty.</p></li><li><p id="x_112"><a name="x_112"></a>It remembers the current parent of the working
- directory. Let's call this changeset
- <code class="literal">orig</code>.</p></li><li><p id="x_113"><a name="x_113"></a>It does the equivalent of a <span class="command"><strong>hg update</strong></span> to sync the working
- directory to the changeset you want to back out. Let's
- call this changeset <code class="literal">backout</code>.</p></li><li><p id="x_114"><a name="x_114"></a>It finds the parent of that changeset. Let's
- call that changeset <code class="literal">parent</code>.</p></li><li><p id="x_115"><a name="x_115"></a>For each file that the
- <code class="literal">backout</code> changeset affected, it does the
- equivalent of a <span class="command"><strong>hg revert -r
- parent</strong></span> on that file, to restore it to the
- contents it had before that changeset was
- committed.</p></li><li><p id="x_116"><a name="x_116"></a>It commits the result as a new changeset.
- This changeset has <code class="literal">backout</code> as its
- parent.</p></li><li><p id="x_117"><a name="x_117"></a>If you specify <code class="option">--merge</code> on the command
- line, it merges with <code class="literal">orig</code>, and commits
- the result of the merge.</p></li></ol></div><p id="x_118"><a name="x_118"></a>An alternative way to implement the <span class="command"><strong>hg backout</strong></span> command would be to
- <span class="command"><strong>hg export</strong></span> the
- to-be-backed-out changeset as a diff, then use the <code class="option">--reverse</code> option to the
- <span class="command"><strong>patch</strong></span> command to reverse the effect of the
- change without fiddling with the working directory. This
- sounds much simpler, but it would not work nearly as
- well.</p><p id="x_119"><a name="x_119"></a>The reason that <span class="command"><strong>hg
- backout</strong></span> does an update, a commit, a merge, and
- another commit is to give the merge machinery the best chance
- to do a good job when dealing with all the changes
- <span class="emphasis"><em>between</em></span> the change you're backing out and
- the current tip.</p><p id="x_11a"><a name="x_11a"></a>If you're backing out a changeset that's 100 revisions
- back in your project's history, the chances that the
- <span class="command"><strong>patch</strong></span> command will be able to apply a
- reverse diff cleanly are not good, because intervening changes
- are likely to have “<span class="quote">broken the context</span>” that
- <span class="command"><strong>patch</strong></span> uses to determine whether it can
- apply a patch (if this sounds like gibberish, see <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:patch" title="Understanding patches">the section called “Understanding patches”</a> for a
- discussion of the <span class="command"><strong>patch</strong></span> command). Also,
- Mercurial's merge machinery will handle files and directories
- being renamed, permission changes, and modifications to binary
- files, none of which <span class="command"><strong>patch</strong></span> can deal
- with.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:undo:aaaiiieee">Changes that should never have been</h2></div></div></div><p id="x_11b"><a name="x_11b"></a>Most of the time, the <span class="command"><strong>hg
- backout</strong></span> command is exactly what you need if you want
- to undo the effects of a change. It leaves a permanent record
- of exactly what you did, both when committing the original
- changeset and when you cleaned up after it.</p><p id="x_11c"><a name="x_11c"></a>On rare occasions, though, you may find that you've
- committed a change that really should not be present in the
- repository at all. For example, it would be very unusual, and
- usually considered a mistake, to commit a software project's
- object files as well as its source files. Object files have
- almost no intrinsic value, and they're <span class="emphasis"><em>big</em></span>,
- so they increase the size of the repository and the amount of
- time it takes to clone or pull changes.</p><p id="x_11d"><a name="x_11d"></a>Before I discuss the options that you have if you commit a
- “<span class="quote">brown paper bag</span>” change (the kind that's so bad
- that you want to pull a brown paper bag over your head), let me
- first discuss some approaches that probably won't work.</p><p id="x_11e"><a name="x_11e"></a>Since Mercurial treats history as
- accumulative—every change builds on top of all changes
- that preceded it—you generally can't just make disastrous
- changes disappear. The one exception is when you've just
- committed a change, and it hasn't been pushed or pulled into
- another repository. That's when you can safely use the <span class="command"><strong>hg rollback</strong></span> command, as I detailed in
- <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:rollback" title="Rolling back a transaction">the section called “Rolling back a transaction”</a>.</p><p id="x_11f"><a name="x_11f"></a>After you've pushed a bad change to another repository, you
- <span class="emphasis"><em>could</em></span> still use <span class="command"><strong>hg
- rollback</strong></span> to make your local copy of the change
- disappear, but it won't have the consequences you want. The
- change will still be present in the remote repository, so it
- will reappear in your local repository the next time you
- pull.</p><p id="x_120"><a name="x_120"></a>If a situation like this arises, and you know which
- repositories your bad change has propagated into, you can
- <span class="emphasis"><em>try</em></span> to get rid of the change from
- <span class="emphasis"><em>every</em></span> one of those repositories. This is,
- of course, not a satisfactory solution: if you miss even a
- single repository while you're expunging, the change is still
- “<span class="quote">in the wild</span>”, and could propagate further.</p><p id="x_121"><a name="x_121"></a>If you've committed one or more changes
- <span class="emphasis"><em>after</em></span> the change that you'd like to see
- disappear, your options are further reduced. Mercurial doesn't
- provide a way to “<span class="quote">punch a hole</span>” in history, leaving
- changesets intact.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394303">Backing out a merge</h3></div></div></div><p id="x_6ba"><a name="x_6ba"></a>Since merges are often complicated, it is not unheard of
- for a merge to be mangled badly, but committed erroneously.
- Mercurial provides an important safeguard against bad merges
- by refusing to commit unresolved files, but human ingenuity
- guarantees that it is still possible to mess a merge up and
- commit it.</p><p id="x_6bb"><a name="x_6bb"></a>Given a bad merge that has been committed, usually the
- best way to approach it is to simply try to repair the damage
- by hand. A complete disaster that cannot be easily fixed up
- by hand ought to be very rare, but the <span class="command"><strong>hg backout</strong></span> command may help in
- making the cleanup easier. It offers a <code class="option">--parent</code> option, which lets
- you specify which parent to revert to when backing out a
- merge.</p><div class="figure"><a name="fig:undo:bad-merge-1"></a><p class="title"><b>Figure 9.5. A bad merge</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-1.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_6bc"><a name="x_6bc"></a>Suppose we have a revision graph like that in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-1" title="Figure 9.5. A bad merge">Figure 9.5, “A bad merge”</a>. What we'd like is to
- <span class="emphasis"><em>redo</em></span> the merge of revisions 2 and
- 3.</p><p id="x_6bd"><a name="x_6bd"></a>One way to do so would be as follows.</p><div class="orderedlist"><ol type="1"><li><p id="x_6be"><a name="x_6be"></a>Call <span class="command"><strong>hg backout --rev=4
- --parent=2</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision
- 4, which is the bad merge, and to when deciding which
- revision to prefer, to choose parent 2, one of the parents
- of the merge. The effect can be seen in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-2" title="Figure 9.6. Backing out the merge, favoring one parent">Figure 9.6, “Backing out the merge, favoring one parent”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-2"></a><p class="title"><b>Figure 9.6. Backing out the merge, favoring one parent</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-2.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6bf"><a name="x_6bf"></a>Call <span class="command"><strong>hg backout --rev=4
- --parent=3</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision
- 4 again, but this time to choose parent 3, the other
- parent of the merge. The result is visible in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-3" title="Figure 9.7. Backing out the merge, favoring the other parent">Figure 9.7, “Backing out the merge, favoring the other
- parent”</a>, in which the repository
- now contains three heads.</p><div class="figure"><a name="fig:undo:bad-merge-3"></a><p class="title"><b>Figure 9.7. Backing out the merge, favoring the other
- parent</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-3.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6c0"><a name="x_6c0"></a>Redo the bad merge by merging the two backout heads,
- which reduces the number of heads in the repository to
- two, as can be seen in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-4" title="Figure 9.8. Merging the backouts">Figure 9.8, “Merging the backouts”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-4"></a><p class="title"><b>Figure 9.8. Merging the backouts</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-4.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6c1"><a name="x_6c1"></a>Merge with the commit that was made after the bad
- merge, as shown in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-5" title="Figure 9.9. Merging the backouts">Figure 9.9, “Merging the backouts”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-5"></a><p class="title"><b>Figure 9.9. Merging the backouts</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-5.png" alt="XXX add text"></div></div></div><br class="figure-break"></li></ol></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394612">Protect yourself from “<span class="quote">escaped</span>”
- changes</h3></div></div></div><p id="x_123"><a name="x_123"></a>If you've committed some changes to your local repository
- and they've been pushed or pulled somewhere else, this isn't
- necessarily a disaster. You can protect yourself ahead of
- time against some classes of bad changeset. This is
- particularly easy if your team usually pulls changes from a
- central repository.</p><p id="x_124"><a name="x_124"></a>By configuring some hooks on that repository to validate
- incoming changesets (see chapter <a class="xref" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks">Chapter 10, <i>Handling repository events with hooks</i></a>),
- you can
- automatically prevent some kinds of bad changeset from being
- pushed to the central repository at all. With such a
- configuration in place, some kinds of bad changeset will
- naturally tend to “<span class="quote">die out</span>” because they can't
- propagate into the central repository. Better yet, this
- happens without any need for explicit intervention.</p><p id="x_125"><a name="x_125"></a>For instance, an incoming change hook that
- verifies that a changeset will actually compile can prevent
- people from inadvertently “<span class="quote">breaking the
- build</span>”.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394667">What to do about sensitive changes that escape</h3></div></div></div><p id="x_6c2"><a name="x_6c2"></a>Even a carefully run project can suffer an unfortunate
- event such as the committing and uncontrolled propagation of a
- file that contains important passwords.</p><p id="x_6c3"><a name="x_6c3"></a>If something like this happens to you, and the information
- that gets accidentally propagated is truly sensitive, your
- first step should be to mitigate the effect of the leak
- without trying to control the leak itself. If you are not 100%
- certain that you know exactly who could have seen the changes,
- you should immediately change passwords, cancel credit cards,
- or find some other way to make sure that the information that
- has leaked is no longer useful. In other words, assume that
- the change has propagated far and wide, and that there's
- nothing more you can do.</p><p id="x_6c4"><a name="x_6c4"></a>You might hope that there would be mechanisms you could
- use to either figure out who has seen a change or to erase the
- change permanently everywhere, but there are good reasons why
- these are not possible.</p><p id="x_6c5"><a name="x_6c5"></a>Mercurial does not provide an audit trail of who has
- pulled changes from a repository, because it is usually either
- impossible to record such information or trivial to spoof it.
- In a multi-user or networked environment, you should thus be
- extremely skeptical of yourself if you think that you have
- identified every place that a sensitive changeset has
- propagated to. Don't forget that people can and will send
- bundles by email, have their backup software save data
- offsite, carry repositories on USB sticks, and find other
- completely innocent ways to confound your attempts to track
- down every copy of a problematic change.</p><p id="x_6c6"><a name="x_6c6"></a>Mercurial also does not provide a way to make a file or
- changeset completely disappear from history, because there is
- no way to enforce its disappearance; someone could easily
- modify their copy of Mercurial to ignore such directives. In
- addition, even if Mercurial provided such a capability,
- someone who simply hadn't pulled a “<span class="quote">make this file
- disappear</span>” changeset wouldn't be affected by it, nor
- would web crawlers visiting at the wrong time, disk backups,
- or other mechanisms. Indeed, no distributed revision control
- system can make data reliably vanish. Providing the illusion
- of such control could easily give a false sense of security,
- and be worse than not providing it at all.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:undo:bisect">Finding the source of a bug</h2></div></div></div><p id="x_126"><a name="x_126"></a>While it's all very well to be able to back out a changeset
- that introduced a bug, this requires that you know which
- changeset to back out. Mercurial provides an invaluable
- command, called <span class="command"><strong>hg bisect</strong></span>, that
- helps you to automate this process and accomplish it very
- efficiently.</p><p id="x_127"><a name="x_127"></a>The idea behind the <span class="command"><strong>hg
- bisect</strong></span> command is that a changeset has introduced
- some change of behavior that you can identify with a simple
- pass/fail test. You don't know which piece of code introduced the
- change, but you know how to test for the presence of the bug.
- The <span class="command"><strong>hg bisect</strong></span> command uses your
- test to direct its search for the changeset that introduced the
- code that caused the bug.</p><p id="x_128"><a name="x_128"></a>Here are a few scenarios to help you understand how you
- might apply this command.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_129"><a name="x_129"></a>The most recent version of your software has a
- bug that you remember wasn't present a few weeks ago, but
- you don't know when it was introduced. Here, your binary
- test checks for the presence of that bug.</p></li><li><p id="x_12a"><a name="x_12a"></a>You fixed a bug in a rush, and now it's time to
- close the entry in your team's bug database. The bug
- database requires a changeset ID when you close an entry,
- but you don't remember which changeset you fixed the bug in.
- Once again, your binary test checks for the presence of the
- bug.</p></li><li><p id="x_12b"><a name="x_12b"></a>Your software works correctly, but runs 15%
- slower than the last time you measured it. You want to know
- which changeset introduced the performance regression. In
- this case, your binary test measures the performance of your
- software, to see whether it's “<span class="quote">fast</span>” or
- “<span class="quote">slow</span>”.</p></li><li><p id="x_12c"><a name="x_12c"></a>The sizes of the components of your project that
- you ship exploded recently, and you suspect that something
- changed in the way you build your project.</p></li></ul></div><p id="x_12d"><a name="x_12d"></a>From these examples, it should be clear that the <span class="command"><strong>hg bisect</strong></span> command is not useful only
- for finding the sources of bugs. You can use it to find any
- “<span class="quote">emergent property</span>” of a repository (anything that
- you can't find from a simple text search of the files in the
- tree) for which you can write a binary test.</p><p id="x_12e"><a name="x_12e"></a>We'll introduce a little bit of terminology here, just to
- make it clear which parts of the search process are your
- responsibility, and which are Mercurial's. A
- <span class="emphasis"><em>test</em></span> is something that
- <span class="emphasis"><em>you</em></span> run when <span class="command"><strong>hg
- bisect</strong></span> chooses a changeset. A
- <span class="emphasis"><em>probe</em></span> is what <span class="command"><strong>hg
- bisect</strong></span> runs to tell whether a revision is good.
- Finally, we'll use the word “<span class="quote">bisect</span>”, as both a
- noun and a verb, to stand in for the phrase “<span class="quote">search using
- the <span class="command"><strong>hg bisect</strong></span>
-
- command</span>”.</p><p id="x_12f"><a name="x_12f"></a>One simple way to automate the searching process would be
- simply to probe every changeset. However, this scales poorly.
- If it took ten minutes to test a single changeset, and you had
- 10,000 changesets in your repository, the exhaustive approach
- would take on average 35 <span class="emphasis"><em>days</em></span> to find the
- changeset that introduced a bug. Even if you knew that the bug
- was introduced by one of the last 500 changesets, and limited
- your search to those, you'd still be looking at over 40 hours to
- find the changeset that introduced your bug.</p><p id="x_130"><a name="x_130"></a>What the <span class="command"><strong>hg bisect</strong></span> command
- does is use its knowledge of the “<span class="quote">shape</span>” of your
- project's revision history to perform a search in time
- proportional to the <span class="emphasis"><em>logarithm</em></span> of the number
- of changesets to check (the kind of search it performs is called
- a dichotomic search). With this approach, searching through
- 10,000 changesets will take less than three hours, even at ten
- minutes per test (the search will require about 14 tests).
- Limit your search to the last hundred changesets, and it will
- take only about an hour (roughly seven tests).</p><p id="x_131"><a name="x_131"></a>The <span class="command"><strong>hg bisect</strong></span> command is
- aware of the “<span class="quote">branchy</span>” nature of a Mercurial
- project's revision history, so it has no problems dealing with
- branches, merges, or multiple heads in a repository. It can
- prune entire branches of history with a single probe, which is
- how it operates so efficiently.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394992">Using the <span class="command"><strong>hg bisect</strong></span>
-
- command</h3></div></div></div><p id="x_132"><a name="x_132"></a>Here's an example of <span class="command"><strong>hg
- bisect</strong></span> in action.</p><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_133"><a name="x_133"></a> In versions 0.9.5 and earlier of Mercurial, <span class="command"><strong>hg bisect</strong></span> was not a core command:
- it was distributed with Mercurial as an extension. This
- section describes the built-in command, not the old
- extension.</p></td></tr></table></div><p id="x_134"><a name="x_134"></a>Now let's create a repository, so that we can try out the
- <span class="command"><strong>hg bisect</strong></span> command in
- isolation.</p><pre id="id395406" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init mybug</code></strong>
-
-<code class="prompt">$</code> <strong class="userinput"><code>cd mybug</code></strong>
-</pre><p id="x_135"><a name="x_135"></a>We'll simulate a project that has a bug in it in a
- simple-minded way: create trivial changes in a loop, and
- nominate one specific change that will have the
- “<span class="quote">bug</span>”. This loop creates 35 changesets, each
- adding a single file to the repository. We'll represent our
- “<span class="quote">bug</span>” with a file that contains the text “<span class="quote">i
- have a gub</span>”.</p><pre id="id395397" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>buggy_change=22</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>for (( i = 0; i < 35; i++ )); do</code></strong>
-
-<code class="prompt">></code> <strong class="userinput"><code> if [[ $i = $buggy_change ]]; then</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> echo 'i have a gub' > myfile$i</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'buggy changeset'</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> else</code></strong>
-
-<code class="prompt">></code> <strong class="userinput"><code> echo 'nothing to see here, move along' > myfile$i</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'normal changeset'</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> fi</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code>done</code></strong>
-
-</pre><p id="x_136"><a name="x_136"></a>The next thing that we'd like to do is figure out how to
- use the <span class="command"><strong>hg bisect</strong></span> command.
- We can use Mercurial's normal built-in help mechanism for
- this.</p><pre id="id395535" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg help bisect</code></strong>
-hg bisect [-gbsr] [-c CMD] [REV]
-
-subdivision search of changesets
-
- This command helps to find changesets which introduce problems.
- To use, mark the earliest changeset you know exhibits the problem
- as bad, then mark the latest changeset which is free from the
- problem as good. Bisect will update your working directory to a
- revision for testing (unless the --noupdate option is specified).
- Once you have performed tests, mark the working directory as bad
- or good and bisect will either update to another candidate changeset
- or announce that it has found the bad revision.
-
- As a shortcut, you can also use the revision argument to mark a
- revision as good or bad without checking it out first.
-
- If you supply a command it will be used for automatic bisection. Its exit
- status will be used as flag to mark revision as bad or good. In case exit
- status is 0 the revision is marked as good, 125 - skipped, 127 (command not
- found) - bisection will be aborted; any other status bigger than 0 will
- mark revision as bad.
-
-options:
-
- -r --reset reset bisect state
- -g --good mark changeset good
- -b --bad mark changeset bad
- -s --skip skip testing changeset
- -c --command use command to check changeset state
- -U --noupdate do not update to target
-
-use "hg -v help bisect" to show global options
-</pre><p id="x_137"><a name="x_137"></a>The <span class="command"><strong>hg bisect</strong></span> command
- works in steps. Each step proceeds as follows.</p><div class="orderedlist"><ol type="1"><li><p id="x_138"><a name="x_138"></a>You run your binary test.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_139"><a name="x_139"></a>If the test succeeded, you tell <span class="command"><strong>hg bisect</strong></span> by running the
- <span class="command"><strong>hg bisect --good</strong></span>
-
- command.</p></li><li><p id="x_13a"><a name="x_13a"></a>If it failed, run the <span class="command"><strong>hg bisect --bad</strong></span>
- command.</p></li></ul></div></li><li><p id="x_13b"><a name="x_13b"></a>The command uses your information to decide
- which changeset to test next.</p></li><li><p id="x_13c"><a name="x_13c"></a>It updates the working directory to that
- changeset, and the process begins again.</p></li></ol></div><p id="x_13d"><a name="x_13d"></a>The process ends when <span class="command"><strong>hg
- bisect</strong></span> identifies a unique changeset that marks
- the point where your test transitioned from
- “<span class="quote">succeeding</span>” to “<span class="quote">failing</span>”.</p><p id="x_13e"><a name="x_13e"></a>To start the search, we must run the <span class="command"><strong>hg bisect --reset</strong></span> command.</p><pre id="id395968" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --reset</code></strong>
-
-</pre><p id="x_13f"><a name="x_13f"></a>In our case, the binary test we use is simple: we check to
- see if any file in the repository contains the string “<span class="quote">i
- have a gub</span>”. If it does, this changeset contains the
- change that “<span class="quote">caused the bug</span>”. By convention, a
- changeset that has the property we're searching for is
- “<span class="quote">bad</span>”, while one that doesn't is
- “<span class="quote">good</span>”.</p><p id="x_140"><a name="x_140"></a>Most of the time, the revision to which the working
- directory is synced (usually the tip) already exhibits the
- problem introduced by the buggy change, so we'll mark it as
- “<span class="quote">bad</span>”.</p><pre id="id396047" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --bad</code></strong>
-</pre><p id="x_141"><a name="x_141"></a>Our next task is to nominate a changeset that we know
- <span class="emphasis"><em>doesn't</em></span> have the bug; the <span class="command"><strong>hg bisect</strong></span> command will
- “<span class="quote">bracket</span>” its search between the first pair of
- good and bad changesets. In our case, we know that revision
- 10 didn't have the bug. (I'll have more words about choosing
- the first “<span class="quote">good</span>” changeset later.)</p><pre id="id396032" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --good 10</code></strong>
-
-Testing changeset 22:b8789808fc48 (24 changesets remaining, ~4 tests)
-0 files updated, 0 files merged, 12 files removed, 0 files unresolved
-</pre><p id="x_142"><a name="x_142"></a>Notice that this command printed some output.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_143"><a name="x_143"></a>It told us how many changesets it must
- consider before it can identify the one that introduced
- the bug, and how many tests that will require.</p></li><li><p id="x_144"><a name="x_144"></a>It updated the working directory to the next
- changeset to test, and told us which changeset it's
- testing.</p></li></ul></div><p id="x_145"><a name="x_145"></a>We now run our test in the working directory. We use the
- <span class="command"><strong>grep</strong></span> command to see if our
- “<span class="quote">bad</span>” file is present in the working directory.
- If it is, this revision is bad; if not, this revision is good.
-
-</p><pre id="id395911" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>if grep -q 'i have a gub' *</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code>then</code></strong>
-
-<code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code>else</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code>fi</code></strong>
-<code class="prompt">$</code> <strong class="userinput"><code>echo this revision is $result</code></strong>
-
-this revision is bad
-<code class="prompt">$</code> <strong class="userinput"><code>hg bisect --$result</code></strong>
-Testing changeset 16:e61fdddff53e (12 changesets remaining, ~3 tests)
-0 files updated, 0 files merged, 6 files removed, 0 files unresolved
-</pre><p>
-
-</p><p id="x_146"><a name="x_146"></a>This test looks like a perfect candidate for automation,
- so let's turn it into a shell function.</p><pre id="id396435" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest() {</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> if grep -q 'i have a gub' *</code></strong>
-
-<code class="prompt">></code> <strong class="userinput"><code> then</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> else</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> fi</code></strong>
-
-<code class="prompt">></code> <strong class="userinput"><code> echo this revision is $result</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code> hg bisect --$result</code></strong>
-<code class="prompt">></code> <strong class="userinput"><code>}</code></strong>
-</pre><p id="x_147"><a name="x_147"></a>We can now run an entire test step with a single command,
- <code class="literal">mytest</code>.</p><pre id="id396403" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
-
-this revision is good
-Testing changeset 19:706df39b003b (6 changesets remaining, ~2 tests)
-3 files updated, 0 files merged, 0 files removed, 0 files unresolved
-</pre><p id="x_148"><a name="x_148"></a>A few more invocations of our canned test step command,
- and we're done.</p><pre id="id396344" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
-this revision is good
-Testing changeset 20:bf7ea9a054e6 (3 changesets remaining, ~1 tests)
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-<code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
-this revision is good
-Testing changeset 21:921391dd45c1 (2 changesets remaining, ~1 tests)
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-<code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
-this revision is good
-The first bad revision is:
-changeset: 22:b8789808fc48
-user: Bryan O'Sullivan <bos@serpentine.com>
-
-date: Tue May 05 06:55:14 2009 +0000
-summary: buggy changeset
-
-</pre><p id="x_149"><a name="x_149"></a>Even though we had 40 changesets to search through, the
- <span class="command"><strong>hg bisect</strong></span> command let us find
- the changeset that introduced our “<span class="quote">bug</span>” with only
- five tests. Because the number of tests that the <span class="command"><strong>hg bisect</strong></span> command performs grows
- logarithmically with the number of changesets to search, the
- advantage that it has over the “<span class="quote">brute force</span>”
- search approach increases with every changeset you add.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396541">Cleaning up after your search</h3></div></div></div><p id="x_14a"><a name="x_14a"></a>When you're finished using the <span class="command"><strong>hg
- bisect</strong></span> command in a repository, you can use the
- <span class="command"><strong>hg bisect --reset</strong></span> command to
- drop the information it was using to drive your search. The
- command doesn't use much space, so it doesn't matter if you
- forget to run this command. However, <span class="command"><strong>hg bisect</strong></span> won't let you start a new
- search in that repository until you do a <span class="command"><strong>hg bisect --reset</strong></span>.</p><pre id="id396936" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --reset</code></strong>
-
-</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id396622">Tips for finding bugs effectively</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396628">Give consistent input</h3></div></div></div><p id="x_14b"><a name="x_14b"></a>The <span class="command"><strong>hg bisect</strong></span> command
- requires that you correctly report the result of every test
- you perform. If you tell it that a test failed when it really
- succeeded, it <span class="emphasis"><em>might</em></span> be able to detect the
- inconsistency. If it can identify an inconsistency in your
- reports, it will tell you that a particular changeset is both
- good and bad. However, it can't do this perfectly; it's about
- as likely to report the wrong changeset as the source of the
- bug.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396884">Automate as much as possible</h3></div></div></div><p id="x_14c"><a name="x_14c"></a>When I started using the <span class="command"><strong>hg
- bisect</strong></span> command, I tried a few times to run my
- tests by hand, on the command line. This is an approach that
- I, at least, am not suited to. After a few tries, I found
- that I was making enough mistakes that I was having to restart
- my searches several times before finally getting correct
- results.</p><p id="x_14d"><a name="x_14d"></a>My initial problems with driving the <span class="command"><strong>hg bisect</strong></span> command by hand occurred
- even with simple searches on small repositories; if the
- problem you're looking for is more subtle, or the number of
- tests that <span class="command"><strong>hg bisect</strong></span> must
- perform increases, the likelihood of operator error ruining
- the search is much higher. Once I started automating my
- tests, I had much better results.</p><p id="x_14e"><a name="x_14e"></a>The key to automated testing is twofold:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_14f"><a name="x_14f"></a>always test for the same symptom, and</p></li><li><p id="x_150"><a name="x_150"></a>always feed consistent input to the <span class="command"><strong>hg bisect</strong></span> command.</p></li></ul></div><p id="x_151"><a name="x_151"></a>In my tutorial example above, the <span class="command"><strong>grep</strong></span>
-
- command tests for the symptom, and the <code class="literal">if</code>
- statement takes the result of this check and ensures that we
- always feed the same input to the <span class="command"><strong>hg
- bisect</strong></span> command. The <code class="literal">mytest</code>
- function marries these together in a reproducible way, so that
- every test is uniform and consistent.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396713">Check your results</h3></div></div></div><p id="x_152"><a name="x_152"></a>Because the output of a <span class="command"><strong>hg
- bisect</strong></span> search is only as good as the input you
- give it, don't take the changeset it reports as the absolute
- truth. A simple way to cross-check its report is to manually
- run your test at each of the following changesets:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_153"><a name="x_153"></a>The changeset that it reports as the first bad
- revision. Your test should still report this as
- bad.</p></li><li><p id="x_154"><a name="x_154"></a>The parent of that changeset (either parent,
- if it's a merge). Your test should report this changeset
- as good.</p></li><li><p id="x_155"><a name="x_155"></a>A child of that changeset. Your test should
- report this changeset as bad.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396770">Beware interference between bugs</h3></div></div></div><p id="x_156"><a name="x_156"></a>It's possible that your search for one bug could be
- disrupted by the presence of another. For example, let's say
- your software crashes at revision 100, and worked correctly at
- revision 50. Unknown to you, someone else introduced a
- different crashing bug at revision 60, and fixed it at
- revision 80. This could distort your results in one of
- several ways.</p><p id="x_157"><a name="x_157"></a>It is possible that this other bug completely
- “<span class="quote">masks</span>” yours, which is to say that it occurs
- before your bug has a chance to manifest itself. If you can't
- avoid that other bug (for example, it prevents your project
- from building), and so can't tell whether your bug is present
- in a particular changeset, the <span class="command"><strong>hg
- bisect</strong></span> command cannot help you directly. Instead,
- you can mark a changeset as untested by running <span class="command"><strong>hg bisect --skip</strong></span>.</p><p id="x_158"><a name="x_158"></a>A different problem could arise if your test for a bug's
- presence is not specific enough. If you check for “<span class="quote">my
- program crashes</span>”, then both your crashing bug and an
- unrelated crashing bug that masks it will look like the same
- thing, and mislead <span class="command"><strong>hg
- bisect</strong></span>.</p><p id="x_159"><a name="x_159"></a>Another useful situation in which to use <span class="command"><strong>hg bisect --skip</strong></span> is if you can't
- test a revision because your project was in a broken and hence
- untestable state at that revision, perhaps because someone
- checked in a change that prevented the project from
- building.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396856">Bracket your search lazily</h3></div></div></div><p id="x_15a"><a name="x_15a"></a>Choosing the first “<span class="quote">good</span>” and
- “<span class="quote">bad</span>” changesets that will mark the end points of
- your search is often easy, but it bears a little discussion
- nevertheless. From the perspective of <span class="command"><strong>hg bisect</strong></span>, the “<span class="quote">newest</span>”
- changeset is conventionally “<span class="quote">bad</span>”, and the older
- changeset is “<span class="quote">good</span>”.</p><p id="x_15b"><a name="x_15b"></a>If you're having trouble remembering when a suitable
- “<span class="quote">good</span>” change was, so that you can tell <span class="command"><strong>hg bisect</strong></span>, you could do worse than
- testing changesets at random. Just remember to eliminate
- contenders that can't possibly exhibit the bug (perhaps
- because the feature with the bug isn't present yet) and those
- where another problem masks the bug (as I discussed
- above).</p><p id="x_15c"><a name="x_15c"></a>Even if you end up “<span class="quote">early</span>” by thousands of
- changesets or months of history, you will only add a handful
- of tests to the total number that <span class="command"><strong>hg
- bisect</strong></span> must perform, thanks to its logarithmic
- behavior.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
- Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="managing-releases-and-branchy-development.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="handling-repository-events-with-hooks.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Managing releases and branchy development </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 10. Handling repository events with hooks</td></tr></table></div><script type="text/javascript">
- var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
- document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
- </script><script type="text/javascript">
- try {
- var pageTracker = _gat._getTracker("UA-1805907-5");
- pageTracker._trackPageview();
- } catch(err) {}</script></body></html>
-