1 <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 |
|
2 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 |
|
3 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 |
|
4 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 |
|
5 well takes a top-notch revision control system. In this chapter, |
|
6 we'll discuss some of the techniques you can use when you find |
|
7 that a problem has crept into your project. Mercurial has some |
|
8 highly capable features that will help you to isolate the sources |
|
9 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 |
|
10 rather more quickly than I can think, which sometimes results |
|
11 in me committing a changeset that is either incomplete or |
|
12 plain wrong. In my case, the usual kind of incomplete |
|
13 changeset is one in which I've created a new source file, but |
|
14 forgotten to <span class="command"><strong>hg add</strong></span> it. A |
|
15 “<span class="quote">plain wrong</span>” changeset is not as common, but no |
|
16 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 |
|
17 mentioned that Mercurial treats each modification of a |
|
18 repository as a <span class="emphasis"><em>transaction</em></span>. Every time |
|
19 you commit a changeset or pull changes from another |
|
20 repository, Mercurial remembers what you did. You can undo, |
|
21 or <span class="emphasis"><em>roll back</em></span>, exactly one of these |
|
22 actions using the <span class="command"><strong>hg rollback</strong></span> |
|
23 |
|
24 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> |
|
25 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: |
|
26 committing a change in which I've created a new file, but |
|
27 forgotten to <span class="command"><strong>hg add</strong></span> |
|
28 it.</p><pre id="id390839" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
29 M a |
|
30 <code class="prompt">$</code> <strong class="userinput"><code>echo b > b</code></strong> |
|
31 |
|
32 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b'</code></strong> |
|
33 </pre><p id="x_d6"><a name="x_d6"></a>Looking at the output of <span class="command"><strong>hg |
|
34 status</strong></span> after the commit immediately confirms the |
|
35 error.</p><pre id="id390541" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
36 ? b |
|
37 <code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong> |
|
38 |
|
39 changeset: 1:f2db1de2ba4f |
|
40 tag: tip |
|
41 user: Bryan O'Sullivan <bos@serpentine.com> |
|
42 date: Tue May 05 06:55:44 2009 +0000 |
|
43 summary: Add file b |
|
44 |
|
45 </pre><p id="x_d7"><a name="x_d7"></a>The commit captured the changes to the file |
|
46 <code class="filename">a</code>, but not the new file |
|
47 <code class="filename">b</code>. If I were to push this changeset to a |
|
48 repository that I shared with a colleague, the chances are |
|
49 high that something in <code class="filename">a</code> would refer to |
|
50 <code class="filename">b</code>, which would not be present in their |
|
51 repository when they pulled my changes. I would thus become |
|
52 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 |
|
53 before I pushed the changeset. I use the <span class="command"><strong>hg rollback</strong></span> command, and Mercurial |
|
54 makes that last changeset vanish.</p><pre id="id391066" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong> |
|
55 |
|
56 rolling back last transaction |
|
57 <code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong> |
|
58 changeset: 0:cde70bc943e1 |
|
59 tag: tip |
|
60 user: Bryan O'Sullivan <bos@serpentine.com> |
|
61 date: Tue May 05 06:55:44 2009 +0000 |
|
62 summary: First commit |
|
63 |
|
64 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
65 M a |
|
66 ? b |
|
67 </pre><p id="x_d9"><a name="x_d9"></a>Notice that the changeset is no longer present in the |
|
68 repository's history, and the working directory once again |
|
69 thinks that the file <code class="filename">a</code> is modified. The |
|
70 commit and rollback have left the working directory exactly as |
|
71 it was prior to the commit; the changeset has been completely |
|
72 erased. I can now safely <span class="command"><strong>hg |
|
73 add</strong></span> the file <code class="filename">b</code>, and rerun my |
|
74 commit.</p><pre id="id391024" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg add b</code></strong> |
|
75 |
|
76 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b, this time for real'</code></strong> |
|
77 </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 |
|
78 development branches of a project in different repositories. |
|
79 Your development team might have one shared repository for |
|
80 your project's “<span class="quote">0.9</span>” release, and another, |
|
81 containing different changes, for the “<span class="quote">1.0</span>” |
|
82 release.</p><p id="x_db"><a name="x_db"></a>Given this, you can imagine that the consequences could be |
|
83 messy if you had a local “<span class="quote">0.9</span>” repository, and |
|
84 accidentally pulled changes from the shared “<span class="quote">1.0</span>” |
|
85 repository into it. At worst, you could be paying |
|
86 insufficient attention, and push those changes into the shared |
|
87 “<span class="quote">0.9</span>” tree, confusing your entire team (but don't |
|
88 worry, we'll return to this horror scenario later). However, |
|
89 it's more likely that you'll notice immediately, because |
|
90 Mercurial will display the URL it's pulling from, or you will |
|
91 see it pull a suspiciously large number of changes into the |
|
92 repository.</p><p id="x_dc"><a name="x_dc"></a>The <span class="command"><strong>hg rollback</strong></span> command |
|
93 will work nicely to expunge all of the changesets that you |
|
94 just pulled. Mercurial groups all changes from one <span class="command"><strong>hg pull</strong></span> into a single transaction, |
|
95 so one <span class="command"><strong>hg rollback</strong></span> is all you |
|
96 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 |
|
97 rollback</strong></span> command drops to zero once you've pushed |
|
98 your changes to another repository. Rolling back a change |
|
99 makes it disappear entirely, but <span class="emphasis"><em>only</em></span> in |
|
100 the repository in which you perform the <span class="command"><strong>hg rollback</strong></span>. Because a rollback |
|
101 eliminates history, there's no way for the disappearance of a |
|
102 change to propagate between repositories.</p><p id="x_de"><a name="x_de"></a>If you've pushed a change to another |
|
103 repository—particularly if it's a shared |
|
104 repository—it has essentially “<span class="quote">escaped into the |
|
105 wild,</span>” and you'll have to recover from your mistake |
|
106 in a different way. If you push a changeset somewhere, then |
|
107 roll it back, then pull from the repository you pushed to, the |
|
108 changeset you thought you'd gotten rid of will simply reappear |
|
109 in your repository.</p><p id="x_df"><a name="x_df"></a>(If you absolutely know for sure that the change |
|
110 you want to roll back is the most recent change in the |
|
111 repository that you pushed to, <span class="emphasis"><em>and</em></span> you |
|
112 know that nobody else could have pulled it from that |
|
113 repository, you can roll back the changeset there, too, but |
|
114 you really should not expect this to work reliably. Sooner or |
|
115 later a change really will make it into a repository that you |
|
116 don't directly control (or have forgotten about), and come |
|
117 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 |
|
118 transaction log; that transaction is the most recent one that |
|
119 occurred in the repository. This means that you can only roll |
|
120 back one transaction. If you expect to be able to roll back |
|
121 one transaction, then its predecessor, this is not the |
|
122 behavior you will get.</p><pre id="id391424" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong> |
|
123 |
|
124 rolling back last transaction |
|
125 <code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong> |
|
126 no rollback information available |
|
127 </pre><p id="x_e1"><a name="x_e1"></a>Once you've rolled back one transaction in a repository, |
|
128 you can't roll back again in that repository until you perform |
|
129 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 |
|
130 really didn't want to change the file at all, and you haven't |
|
131 yet committed your changes, the <span class="command"><strong>hg |
|
132 revert</strong></span> command is the one you'll need. It looks at |
|
133 the changeset that's the parent of the working directory, and |
|
134 restores the contents of the file to their state as of that |
|
135 changeset. (That's a long-winded way of saying that, in the |
|
136 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 |
|
137 revert</strong></span> command works with yet another small example. |
|
138 We'll begin by modifying a file that Mercurial is already |
|
139 tracking.</p><pre id="id391316" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong> |
|
140 |
|
141 original content |
|
142 <code class="prompt">$</code> <strong class="userinput"><code>echo unwanted change >> file</code></strong> |
|
143 <code class="prompt">$</code> <strong class="userinput"><code>hg diff file</code></strong> |
|
144 diff -r b52afd4afc59 file |
|
145 --- a/file Tue May 05 06:55:32 2009 +0000 |
|
146 +++ b/file Tue May 05 06:55:32 2009 +0000 |
|
147 @@ -1,1 +1,2 @@ |
|
148 original content |
|
149 +unwanted change |
|
150 </pre><p id="x_e4"><a name="x_e4"></a>If we don't |
|
151 want that change, we can simply <span class="command"><strong>hg |
|
152 revert</strong></span> the file.</p><pre id="id391251" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
153 |
|
154 M file |
|
155 <code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong> |
|
156 <code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong> |
|
157 original content |
|
158 </pre><p id="x_e5"><a name="x_e5"></a>The <span class="command"><strong>hg revert</strong></span> command |
|
159 provides us with an extra degree of safety by saving our |
|
160 modified file with a <code class="filename">.orig</code> |
|
161 extension.</p><pre id="id391767" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
162 |
|
163 ? file.orig |
|
164 <code class="prompt">$</code> <strong class="userinput"><code>cat file.orig</code></strong> |
|
165 original content |
|
166 unwanted change |
|
167 </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 |
|
168 Mercurial to manage files with <code class="filename">.orig</code> |
|
169 extensions or that you even care about the contents of such |
|
170 files. Just in case, though, it's useful to remember that |
|
171 <span class="command"><strong>hg revert</strong></span> will |
|
172 unconditionally overwrite an existing file with a |
|
173 <code class="filename">.orig</code> extension. For instance, if you |
|
174 already have a file named <code class="filename">foo.orig</code> when |
|
175 you revert <code class="filename">foo</code>, the contents of |
|
176 <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 |
|
177 will describe each of these in more detail in the section that |
|
178 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 |
|
179 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 |
|
180 file, it will undo the “<span class="quote">added</span>” state of the |
|
181 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, |
|
182 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 |
|
183 remove</strong></span> command to remove a file, it will undo |
|
184 the “<span class="quote">removed</span>” state of the file, and restore |
|
185 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 |
|
186 useful for more than just modified files. It lets you reverse |
|
187 the results of all of Mercurial's file management |
|
188 commands—<span class="command"><strong>hg add</strong></span>, |
|
189 <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, |
|
190 then decide that in fact you don't want Mercurial to track it, |
|
191 use <span class="command"><strong>hg revert</strong></span> to undo the |
|
192 add. Don't worry; Mercurial will not modify the file in any |
|
193 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> |
|
194 |
|
195 <code class="prompt">$</code> <strong class="userinput"><code>hg add oops</code></strong> |
|
196 <code class="prompt">$</code> <strong class="userinput"><code>hg status oops</code></strong> |
|
197 A oops |
|
198 <code class="prompt">$</code> <strong class="userinput"><code>hg revert oops</code></strong> |
|
199 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
200 |
|
201 ? oops |
|
202 </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 |
|
203 <span class="command"><strong>hg revert</strong></span> to restore it to |
|
204 the contents it had as of the parent of the working directory. |
|
205 |
|
206 </p><pre id="id392036" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg remove file</code></strong> |
|
207 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
208 R file |
|
209 |
|
210 <code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong> |
|
211 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
212 <code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong> |
|
213 file |
|
214 </pre><p> |
|
215 |
|
216 This works just as |
|
217 well for a file that you deleted by hand, without telling |
|
218 Mercurial (recall that in Mercurial terminology, this kind of |
|
219 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> |
|
220 |
|
221 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
222 ! file |
|
223 <code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong> |
|
224 <code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong> |
|
225 file |
|
226 </pre><p id="x_ee"><a name="x_ee"></a>If you revert a <span class="command"><strong>hg copy</strong></span>, |
|
227 the copied-to file remains in your working directory |
|
228 afterwards, untracked. Since a copy doesn't affect the |
|
229 copied-from file in any way, Mercurial doesn't do anything |
|
230 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> |
|
231 |
|
232 <code class="prompt">$</code> <strong class="userinput"><code>hg revert new-file</code></strong> |
|
233 <code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong> |
|
234 ? new-file |
|
235 </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 |
|
236 <span class="emphasis"><em>a</em></span>, and another change |
|
237 <span class="emphasis"><em>b</em></span> on top of it; you then realise that |
|
238 change <span class="emphasis"><em>a</em></span> was incorrect. Mercurial lets you |
|
239 “<span class="quote">back out</span>” an entire changeset automatically, and |
|
240 building blocks that let you reverse part of a changeset by |
|
241 hand.</p><p id="x_f6"><a name="x_f6"></a>Before you read this section, here's something to |
|
242 keep in mind: the <span class="command"><strong>hg backout</strong></span> |
|
243 |
|
244 command undoes the effect of a change by |
|
245 <span class="emphasis"><em>adding</em></span> to your repository's history, not by |
|
246 modifying or erasing it. It's the right tool to use if you're |
|
247 fixing bugs, but not if you're trying to undo some change that |
|
248 has catastrophic consequences. To deal with those, see |
|
249 <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 |
|
250 lets you “<span class="quote">undo</span>” the effects of an entire |
|
251 changeset in an automated fashion. Because Mercurial's |
|
252 history is immutable, this command <span class="emphasis"><em>does |
|
253 not</em></span> get rid of the changeset you want to undo. |
|
254 Instead, it creates a new changeset that |
|
255 <span class="emphasis"><em>reverses</em></span> the effect of the to-be-undone |
|
256 changeset.</p><p id="x_f8"><a name="x_f8"></a>The operation of the <span class="command"><strong>hg |
|
257 backout</strong></span> command is a little intricate, so let's |
|
258 illustrate it with some examples. First, we'll create a |
|
259 repository with some simple changes.</p><pre id="id392685" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init myrepo</code></strong> |
|
260 |
|
261 <code class="prompt">$</code> <strong class="userinput"><code>cd myrepo</code></strong> |
|
262 <code class="prompt">$</code> <strong class="userinput"><code>echo first change >> myfile</code></strong> |
|
263 <code class="prompt">$</code> <strong class="userinput"><code>hg add myfile</code></strong> |
|
264 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'first change'</code></strong> |
|
265 |
|
266 <code class="prompt">$</code> <strong class="userinput"><code>echo second change >> myfile</code></strong> |
|
267 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'second change'</code></strong> |
|
268 </pre><p id="x_f9"><a name="x_f9"></a>The <span class="command"><strong>hg backout</strong></span> command |
|
269 takes a single changeset ID as its argument; this is the |
|
270 changeset to back out. Normally, <span class="command"><strong>hg |
|
271 backout</strong></span> will drop you into a text editor to write |
|
272 a commit message, so you can record why you're backing the |
|
273 change out. In this example, we provide a commit message on |
|
274 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 |
|
275 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> |
|
276 |
|
277 reverting myfile |
|
278 changeset 2:01adc4672142 backs out changeset 1:7e341ee3be7a |
|
279 <code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong> |
|
280 first change |
|
281 </pre><p id="x_fb"><a name="x_fb"></a>You can see that the second line from |
|
282 <code class="filename">myfile</code> is no longer present. Taking a |
|
283 look at the output of <span class="command"><strong>hg log</strong></span> |
|
284 gives us an idea of what the <span class="command"><strong>hg |
|
285 backout</strong></span> command has done. |
|
286 |
|
287 |
|
288 </p><pre id="id392554" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong> |
|
289 2[tip] 01adc4672142 2009-05-05 06:55 +0000 bos |
|
290 back out second change |
|
291 |
|
292 1 7e341ee3be7a 2009-05-05 06:55 +0000 bos |
|
293 second change |
|
294 |
|
295 0 56b97fc928f2 2009-05-05 06:55 +0000 bos |
|
296 first change |
|
297 |
|
298 </pre><p> |
|
299 |
|
300 Notice that the new changeset |
|
301 that <span class="command"><strong>hg backout</strong></span> has created |
|
302 is a child of the changeset we backed out. It's easier to see |
|
303 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 |
|
304 graphical view of the change history. As you can see, the |
|
305 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 |
|
306 you committed, pass the <code class="option">--merge</code> option to the |
|
307 <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> |
|
308 |
|
309 <code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo non-tip-repo</code></strong> |
|
310 requesting all changes |
|
311 adding changesets |
|
312 adding manifests |
|
313 adding file changes |
|
314 added 2 changesets with 2 changes to 1 files |
|
315 updating working directory |
|
316 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
317 <code class="prompt">$</code> <strong class="userinput"><code>cd non-tip-repo</code></strong> |
|
318 </pre><p id="x_fe"><a name="x_fe"></a>This makes backing out any changeset a |
|
319 “<span class="quote">one-shot</span>” operation that's usually simple and |
|
320 fast.</p><pre id="id392845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo third change >> myfile</code></strong> |
|
321 |
|
322 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong> |
|
323 <code class="prompt">$</code> <strong class="userinput"><code>hg backout --merge -m 'back out second change' 1</code></strong> |
|
324 reverting myfile |
|
325 created new head |
|
326 changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a |
|
327 merging with changeset 3:abc7fd860049 |
|
328 merging myfile |
|
329 0 files updated, 1 files merged, 0 files removed, 0 files unresolved |
|
330 (branch merge, don't forget to commit) |
|
331 </pre><p id="x_ff"><a name="x_ff"></a>If you take a look at the contents of |
|
332 <code class="filename">myfile</code> after the backout finishes, you'll |
|
333 see that the first and third changes are present, but not the |
|
334 second.</p><pre id="id392886" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong> |
|
335 |
|
336 first change |
|
337 third change |
|
338 </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 |
|
339 hg backout command”</a> illustrates, Mercurial |
|
340 still commits one change in this kind of situation (the |
|
341 box-shaped node is the ones that Mercurial commits |
|
342 automatically), but the revision graph now looks different. |
|
343 Before Mercurial begins the backout process, it first |
|
344 remembers what the current parent of the working directory is. |
|
345 It then backs out the target changeset, and commits that as a |
|
346 changeset. Finally, it merges back to the previous parent of |
|
347 the working directory, but notice that it <span class="emphasis"><em>does not |
|
348 commit</em></span> the result of the merge. The repository |
|
349 now contains two heads, and the working directory is in a |
|
350 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 |
|
351 <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 |
|
352 were</span>”, only with some extra history that undoes the |
|
353 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 |
|
354 of the merge that it performed. The reason lies in Mercurial |
|
355 behaving conservatively: a merge naturally has more scope for |
|
356 error than simply undoing the effect of the tip changeset, |
|
357 so your work will be safest if you first inspect (and test!) |
|
358 the result of the merge, <span class="emphasis"><em>then</em></span> commit |
|
359 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 |
|
360 “<span class="quote">right thing</span>” whether or not the changeset |
|
361 you're backing out is the tip (i.e. it won't try to merge if |
|
362 it's backing out the tip, since there's no need), you should |
|
363 <span class="emphasis"><em>always</em></span> use this option when you run the |
|
364 <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 |
|
365 out a change, the <span class="command"><strong>hg backout</strong></span> |
|
366 |
|
367 command lets you decide how to merge a backout changeset. |
|
368 Taking control of the backout process by hand is something you |
|
369 will rarely need to do, but it can be useful to understand |
|
370 what the <span class="command"><strong>hg backout</strong></span> command |
|
371 is doing for you automatically. To illustrate this, let's |
|
372 clone our first repository, but omit the backout change that |
|
373 it contains.</p><pre id="id393568" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong> |
|
374 <code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo newrepo</code></strong> |
|
375 requesting all changes |
|
376 adding changesets |
|
377 adding manifests |
|
378 adding file changes |
|
379 added 2 changesets with 2 changes to 1 files |
|
380 updating working directory |
|
381 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
382 <code class="prompt">$</code> <strong class="userinput"><code>cd newrepo</code></strong> |
|
383 |
|
384 </pre><p id="x_106"><a name="x_106"></a>As with our |
|
385 earlier example, We'll commit a third changeset, then back out |
|
386 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> |
|
387 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong> |
|
388 <code class="prompt">$</code> <strong class="userinput"><code>hg backout -m 'back out second change' 1</code></strong> |
|
389 reverting myfile |
|
390 created new head |
|
391 changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a |
|
392 the backout changeset is a new head - do not forget to merge |
|
393 (use "backout --merge" if you want to auto-merge) |
|
394 </pre><p id="x_107"><a name="x_107"></a>Our new changeset is again a descendant of the changeset |
|
395 we backout out; it's thus a new head, <span class="emphasis"><em>not</em></span> |
|
396 |
|
397 a descendant of the changeset that was the tip. The <span class="command"><strong>hg backout</strong></span> command was quite |
|
398 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> |
|
399 3[tip]:1 abc7fd860049 2009-05-05 06:55 +0000 bos |
|
400 back out second change |
|
401 |
|
402 2 bae4005ddac4 2009-05-05 06:55 +0000 bos |
|
403 third change |
|
404 |
|
405 1 7e341ee3be7a 2009-05-05 06:55 +0000 bos |
|
406 second change |
|
407 |
|
408 0 56b97fc928f2 2009-05-05 06:55 +0000 bos |
|
409 first change |
|
410 |
|
411 </pre><p id="x_108"><a name="x_108"></a>Again, it's easier to see what has happened by looking at |
|
412 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 |
|
413 that when we use <span class="command"><strong>hg backout</strong></span> |
|
414 to back out a change other than the tip, Mercurial adds a new |
|
415 head to the repository (the change it committed is |
|
416 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> |
|
417 |
|
418 command has completed, it leaves the new |
|
419 “<span class="quote">backout</span>” changeset as the parent of the working |
|
420 directory.</p><pre id="id393912" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong> |
|
421 changeset: 2:bae4005ddac4 |
|
422 user: Bryan O'Sullivan <bos@serpentine.com> |
|
423 date: Tue May 05 06:55:12 2009 +0000 |
|
424 summary: third change |
|
425 |
|
426 </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> |
|
427 |
|
428 changeset: 3:abc7fd860049 |
|
429 tag: tip |
|
430 parent: 1:7e341ee3be7a |
|
431 user: Bryan O'Sullivan <bos@serpentine.com> |
|
432 date: Tue May 05 06:55:12 2009 +0000 |
|
433 summary: back out second change |
|
434 |
|
435 changeset: 2:bae4005ddac4 |
|
436 user: Bryan O'Sullivan <bos@serpentine.com> |
|
437 date: Tue May 05 06:55:12 2009 +0000 |
|
438 summary: third change |
|
439 |
|
440 </pre><p id="x_10c"><a name="x_10c"></a>Let's think about what we expect to see as the contents of |
|
441 <code class="filename">myfile</code> now. The first change should be |
|
442 present, because we've never backed it out. The second change |
|
443 should be missing, as that's the change we backed out. Since |
|
444 the history graph shows the third change as a separate head, |
|
445 we <span class="emphasis"><em>don't</em></span> expect to see the third change |
|
446 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> |
|
447 |
|
448 first change |
|
449 </pre><p id="x_10d"><a name="x_10d"></a>To get the third change back into the file, we just do a |
|
450 normal merge of our two heads.</p><pre id="id393845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong> |
|
451 abort: outstanding uncommitted changes |
|
452 <code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'merged backout with previous tip'</code></strong> |
|
453 <code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong> |
|
454 first change |
|
455 </pre><p id="x_10e"><a name="x_10e"></a>Afterwards, the graphical history of our |
|
456 repository looks like |
|
457 <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 |
|
458 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 |
|
459 “<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 |
|
460 directory. Let's call this changeset |
|
461 <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 |
|
462 directory to the changeset you want to back out. Let's |
|
463 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 |
|
464 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 |
|
465 <code class="literal">backout</code> changeset affected, it does the |
|
466 equivalent of a <span class="command"><strong>hg revert -r |
|
467 parent</strong></span> on that file, to restore it to the |
|
468 contents it had before that changeset was |
|
469 committed.</p></li><li><p id="x_116"><a name="x_116"></a>It commits the result as a new changeset. |
|
470 This changeset has <code class="literal">backout</code> as its |
|
471 parent.</p></li><li><p id="x_117"><a name="x_117"></a>If you specify <code class="option">--merge</code> on the command |
|
472 line, it merges with <code class="literal">orig</code>, and commits |
|
473 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 |
|
474 <span class="command"><strong>hg export</strong></span> the |
|
475 to-be-backed-out changeset as a diff, then use the <code class="option">--reverse</code> option to the |
|
476 <span class="command"><strong>patch</strong></span> command to reverse the effect of the |
|
477 change without fiddling with the working directory. This |
|
478 sounds much simpler, but it would not work nearly as |
|
479 well.</p><p id="x_119"><a name="x_119"></a>The reason that <span class="command"><strong>hg |
|
480 backout</strong></span> does an update, a commit, a merge, and |
|
481 another commit is to give the merge machinery the best chance |
|
482 to do a good job when dealing with all the changes |
|
483 <span class="emphasis"><em>between</em></span> the change you're backing out and |
|
484 the current tip.</p><p id="x_11a"><a name="x_11a"></a>If you're backing out a changeset that's 100 revisions |
|
485 back in your project's history, the chances that the |
|
486 <span class="command"><strong>patch</strong></span> command will be able to apply a |
|
487 reverse diff cleanly are not good, because intervening changes |
|
488 are likely to have “<span class="quote">broken the context</span>” that |
|
489 <span class="command"><strong>patch</strong></span> uses to determine whether it can |
|
490 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 |
|
491 discussion of the <span class="command"><strong>patch</strong></span> command). Also, |
|
492 Mercurial's merge machinery will handle files and directories |
|
493 being renamed, permission changes, and modifications to binary |
|
494 files, none of which <span class="command"><strong>patch</strong></span> can deal |
|
495 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 |
|
496 backout</strong></span> command is exactly what you need if you want |
|
497 to undo the effects of a change. It leaves a permanent record |
|
498 of exactly what you did, both when committing the original |
|
499 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 |
|
500 committed a change that really should not be present in the |
|
501 repository at all. For example, it would be very unusual, and |
|
502 usually considered a mistake, to commit a software project's |
|
503 object files as well as its source files. Object files have |
|
504 almost no intrinsic value, and they're <span class="emphasis"><em>big</em></span>, |
|
505 so they increase the size of the repository and the amount of |
|
506 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 |
|
507 “<span class="quote">brown paper bag</span>” change (the kind that's so bad |
|
508 that you want to pull a brown paper bag over your head), let me |
|
509 first discuss some approaches that probably won't work.</p><p id="x_11e"><a name="x_11e"></a>Since Mercurial treats history as |
|
510 accumulative—every change builds on top of all changes |
|
511 that preceded it—you generally can't just make disastrous |
|
512 changes disappear. The one exception is when you've just |
|
513 committed a change, and it hasn't been pushed or pulled into |
|
514 another repository. That's when you can safely use the <span class="command"><strong>hg rollback</strong></span> command, as I detailed in |
|
515 <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 |
|
516 <span class="emphasis"><em>could</em></span> still use <span class="command"><strong>hg |
|
517 rollback</strong></span> to make your local copy of the change |
|
518 disappear, but it won't have the consequences you want. The |
|
519 change will still be present in the remote repository, so it |
|
520 will reappear in your local repository the next time you |
|
521 pull.</p><p id="x_120"><a name="x_120"></a>If a situation like this arises, and you know which |
|
522 repositories your bad change has propagated into, you can |
|
523 <span class="emphasis"><em>try</em></span> to get rid of the change from |
|
524 <span class="emphasis"><em>every</em></span> one of those repositories. This is, |
|
525 of course, not a satisfactory solution: if you miss even a |
|
526 single repository while you're expunging, the change is still |
|
527 “<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 |
|
528 <span class="emphasis"><em>after</em></span> the change that you'd like to see |
|
529 disappear, your options are further reduced. Mercurial doesn't |
|
530 provide a way to “<span class="quote">punch a hole</span>” in history, leaving |
|
531 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 |
|
532 for a merge to be mangled badly, but committed erroneously. |
|
533 Mercurial provides an important safeguard against bad merges |
|
534 by refusing to commit unresolved files, but human ingenuity |
|
535 guarantees that it is still possible to mess a merge up and |
|
536 commit it.</p><p id="x_6bb"><a name="x_6bb"></a>Given a bad merge that has been committed, usually the |
|
537 best way to approach it is to simply try to repair the damage |
|
538 by hand. A complete disaster that cannot be easily fixed up |
|
539 by hand ought to be very rare, but the <span class="command"><strong>hg backout</strong></span> command may help in |
|
540 making the cleanup easier. It offers a <code class="option">--parent</code> option, which lets |
|
541 you specify which parent to revert to when backing out a |
|
542 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 |
|
543 <span class="emphasis"><em>redo</em></span> the merge of revisions 2 and |
|
544 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 |
|
545 --parent=2</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision |
|
546 4, which is the bad merge, and to when deciding which |
|
547 revision to prefer, to choose parent 2, one of the parents |
|
548 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 |
|
549 --parent=3</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision |
|
550 4 again, but this time to choose parent 3, the other |
|
551 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 |
|
552 parent”</a>, in which the repository |
|
553 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 |
|
554 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, |
|
555 which reduces the number of heads in the repository to |
|
556 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 |
|
557 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>” |
|
558 changes</h3></div></div></div><p id="x_123"><a name="x_123"></a>If you've committed some changes to your local repository |
|
559 and they've been pushed or pulled somewhere else, this isn't |
|
560 necessarily a disaster. You can protect yourself ahead of |
|
561 time against some classes of bad changeset. This is |
|
562 particularly easy if your team usually pulls changes from a |
|
563 central repository.</p><p id="x_124"><a name="x_124"></a>By configuring some hooks on that repository to validate |
|
564 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>), |
|
565 you can |
|
566 automatically prevent some kinds of bad changeset from being |
|
567 pushed to the central repository at all. With such a |
|
568 configuration in place, some kinds of bad changeset will |
|
569 naturally tend to “<span class="quote">die out</span>” because they can't |
|
570 propagate into the central repository. Better yet, this |
|
571 happens without any need for explicit intervention.</p><p id="x_125"><a name="x_125"></a>For instance, an incoming change hook that |
|
572 verifies that a changeset will actually compile can prevent |
|
573 people from inadvertently “<span class="quote">breaking the |
|
574 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 |
|
575 event such as the committing and uncontrolled propagation of a |
|
576 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 |
|
577 that gets accidentally propagated is truly sensitive, your |
|
578 first step should be to mitigate the effect of the leak |
|
579 without trying to control the leak itself. If you are not 100% |
|
580 certain that you know exactly who could have seen the changes, |
|
581 you should immediately change passwords, cancel credit cards, |
|
582 or find some other way to make sure that the information that |
|
583 has leaked is no longer useful. In other words, assume that |
|
584 the change has propagated far and wide, and that there's |
|
585 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 |
|
586 use to either figure out who has seen a change or to erase the |
|
587 change permanently everywhere, but there are good reasons why |
|
588 these are not possible.</p><p id="x_6c5"><a name="x_6c5"></a>Mercurial does not provide an audit trail of who has |
|
589 pulled changes from a repository, because it is usually either |
|
590 impossible to record such information or trivial to spoof it. |
|
591 In a multi-user or networked environment, you should thus be |
|
592 extremely skeptical of yourself if you think that you have |
|
593 identified every place that a sensitive changeset has |
|
594 propagated to. Don't forget that people can and will send |
|
595 bundles by email, have their backup software save data |
|
596 offsite, carry repositories on USB sticks, and find other |
|
597 completely innocent ways to confound your attempts to track |
|
598 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 |
|
599 changeset completely disappear from history, because there is |
|
600 no way to enforce its disappearance; someone could easily |
|
601 modify their copy of Mercurial to ignore such directives. In |
|
602 addition, even if Mercurial provided such a capability, |
|
603 someone who simply hadn't pulled a “<span class="quote">make this file |
|
604 disappear</span>” changeset wouldn't be affected by it, nor |
|
605 would web crawlers visiting at the wrong time, disk backups, |
|
606 or other mechanisms. Indeed, no distributed revision control |
|
607 system can make data reliably vanish. Providing the illusion |
|
608 of such control could easily give a false sense of security, |
|
609 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 |
|
610 that introduced a bug, this requires that you know which |
|
611 changeset to back out. Mercurial provides an invaluable |
|
612 command, called <span class="command"><strong>hg bisect</strong></span>, that |
|
613 helps you to automate this process and accomplish it very |
|
614 efficiently.</p><p id="x_127"><a name="x_127"></a>The idea behind the <span class="command"><strong>hg |
|
615 bisect</strong></span> command is that a changeset has introduced |
|
616 some change of behavior that you can identify with a simple |
|
617 pass/fail test. You don't know which piece of code introduced the |
|
618 change, but you know how to test for the presence of the bug. |
|
619 The <span class="command"><strong>hg bisect</strong></span> command uses your |
|
620 test to direct its search for the changeset that introduced the |
|
621 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 |
|
622 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 |
|
623 bug that you remember wasn't present a few weeks ago, but |
|
624 you don't know when it was introduced. Here, your binary |
|
625 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 |
|
626 close the entry in your team's bug database. The bug |
|
627 database requires a changeset ID when you close an entry, |
|
628 but you don't remember which changeset you fixed the bug in. |
|
629 Once again, your binary test checks for the presence of the |
|
630 bug.</p></li><li><p id="x_12b"><a name="x_12b"></a>Your software works correctly, but runs 15% |
|
631 slower than the last time you measured it. You want to know |
|
632 which changeset introduced the performance regression. In |
|
633 this case, your binary test measures the performance of your |
|
634 software, to see whether it's “<span class="quote">fast</span>” or |
|
635 “<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 |
|
636 you ship exploded recently, and you suspect that something |
|
637 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 |
|
638 for finding the sources of bugs. You can use it to find any |
|
639 “<span class="quote">emergent property</span>” of a repository (anything that |
|
640 you can't find from a simple text search of the files in the |
|
641 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 |
|
642 make it clear which parts of the search process are your |
|
643 responsibility, and which are Mercurial's. A |
|
644 <span class="emphasis"><em>test</em></span> is something that |
|
645 <span class="emphasis"><em>you</em></span> run when <span class="command"><strong>hg |
|
646 bisect</strong></span> chooses a changeset. A |
|
647 <span class="emphasis"><em>probe</em></span> is what <span class="command"><strong>hg |
|
648 bisect</strong></span> runs to tell whether a revision is good. |
|
649 Finally, we'll use the word “<span class="quote">bisect</span>”, as both a |
|
650 noun and a verb, to stand in for the phrase “<span class="quote">search using |
|
651 the <span class="command"><strong>hg bisect</strong></span> |
|
652 |
|
653 command</span>”.</p><p id="x_12f"><a name="x_12f"></a>One simple way to automate the searching process would be |
|
654 simply to probe every changeset. However, this scales poorly. |
|
655 If it took ten minutes to test a single changeset, and you had |
|
656 10,000 changesets in your repository, the exhaustive approach |
|
657 would take on average 35 <span class="emphasis"><em>days</em></span> to find the |
|
658 changeset that introduced a bug. Even if you knew that the bug |
|
659 was introduced by one of the last 500 changesets, and limited |
|
660 your search to those, you'd still be looking at over 40 hours to |
|
661 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 |
|
662 does is use its knowledge of the “<span class="quote">shape</span>” of your |
|
663 project's revision history to perform a search in time |
|
664 proportional to the <span class="emphasis"><em>logarithm</em></span> of the number |
|
665 of changesets to check (the kind of search it performs is called |
|
666 a dichotomic search). With this approach, searching through |
|
667 10,000 changesets will take less than three hours, even at ten |
|
668 minutes per test (the search will require about 14 tests). |
|
669 Limit your search to the last hundred changesets, and it will |
|
670 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 |
|
671 aware of the “<span class="quote">branchy</span>” nature of a Mercurial |
|
672 project's revision history, so it has no problems dealing with |
|
673 branches, merges, or multiple heads in a repository. It can |
|
674 prune entire branches of history with a single probe, which is |
|
675 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> |
|
676 |
|
677 command</h3></div></div></div><p id="x_132"><a name="x_132"></a>Here's an example of <span class="command"><strong>hg |
|
678 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: |
|
679 it was distributed with Mercurial as an extension. This |
|
680 section describes the built-in command, not the old |
|
681 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 |
|
682 <span class="command"><strong>hg bisect</strong></span> command in |
|
683 isolation.</p><pre id="id395406" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init mybug</code></strong> |
|
684 |
|
685 <code class="prompt">$</code> <strong class="userinput"><code>cd mybug</code></strong> |
|
686 </pre><p id="x_135"><a name="x_135"></a>We'll simulate a project that has a bug in it in a |
|
687 simple-minded way: create trivial changes in a loop, and |
|
688 nominate one specific change that will have the |
|
689 “<span class="quote">bug</span>”. This loop creates 35 changesets, each |
|
690 adding a single file to the repository. We'll represent our |
|
691 “<span class="quote">bug</span>” with a file that contains the text “<span class="quote">i |
|
692 have a gub</span>”.</p><pre id="id395397" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>buggy_change=22</code></strong> |
|
693 <code class="prompt">$</code> <strong class="userinput"><code>for (( i = 0; i < 35; i++ )); do</code></strong> |
|
694 |
|
695 <code class="prompt">></code> <strong class="userinput"><code> if [[ $i = $buggy_change ]]; then</code></strong> |
|
696 <code class="prompt">></code> <strong class="userinput"><code> echo 'i have a gub' > myfile$i</code></strong> |
|
697 <code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'buggy changeset'</code></strong> |
|
698 <code class="prompt">></code> <strong class="userinput"><code> else</code></strong> |
|
699 |
|
700 <code class="prompt">></code> <strong class="userinput"><code> echo 'nothing to see here, move along' > myfile$i</code></strong> |
|
701 <code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'normal changeset'</code></strong> |
|
702 <code class="prompt">></code> <strong class="userinput"><code> fi</code></strong> |
|
703 <code class="prompt">></code> <strong class="userinput"><code>done</code></strong> |
|
704 |
|
705 </pre><p id="x_136"><a name="x_136"></a>The next thing that we'd like to do is figure out how to |
|
706 use the <span class="command"><strong>hg bisect</strong></span> command. |
|
707 We can use Mercurial's normal built-in help mechanism for |
|
708 this.</p><pre id="id395535" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg help bisect</code></strong> |
|
709 hg bisect [-gbsr] [-c CMD] [REV] |
|
710 |
|
711 subdivision search of changesets |
|
712 |
|
713 This command helps to find changesets which introduce problems. |
|
714 To use, mark the earliest changeset you know exhibits the problem |
|
715 as bad, then mark the latest changeset which is free from the |
|
716 problem as good. Bisect will update your working directory to a |
|
717 revision for testing (unless the --noupdate option is specified). |
|
718 Once you have performed tests, mark the working directory as bad |
|
719 or good and bisect will either update to another candidate changeset |
|
720 or announce that it has found the bad revision. |
|
721 |
|
722 As a shortcut, you can also use the revision argument to mark a |
|
723 revision as good or bad without checking it out first. |
|
724 |
|
725 If you supply a command it will be used for automatic bisection. Its exit |
|
726 status will be used as flag to mark revision as bad or good. In case exit |
|
727 status is 0 the revision is marked as good, 125 - skipped, 127 (command not |
|
728 found) - bisection will be aborted; any other status bigger than 0 will |
|
729 mark revision as bad. |
|
730 |
|
731 options: |
|
732 |
|
733 -r --reset reset bisect state |
|
734 -g --good mark changeset good |
|
735 -b --bad mark changeset bad |
|
736 -s --skip skip testing changeset |
|
737 -c --command use command to check changeset state |
|
738 -U --noupdate do not update to target |
|
739 |
|
740 use "hg -v help bisect" to show global options |
|
741 </pre><p id="x_137"><a name="x_137"></a>The <span class="command"><strong>hg bisect</strong></span> command |
|
742 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 |
|
743 <span class="command"><strong>hg bisect --good</strong></span> |
|
744 |
|
745 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> |
|
746 command.</p></li></ul></div></li><li><p id="x_13b"><a name="x_13b"></a>The command uses your information to decide |
|
747 which changeset to test next.</p></li><li><p id="x_13c"><a name="x_13c"></a>It updates the working directory to that |
|
748 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 |
|
749 bisect</strong></span> identifies a unique changeset that marks |
|
750 the point where your test transitioned from |
|
751 “<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> |
|
752 |
|
753 </pre><p id="x_13f"><a name="x_13f"></a>In our case, the binary test we use is simple: we check to |
|
754 see if any file in the repository contains the string “<span class="quote">i |
|
755 have a gub</span>”. If it does, this changeset contains the |
|
756 change that “<span class="quote">caused the bug</span>”. By convention, a |
|
757 changeset that has the property we're searching for is |
|
758 “<span class="quote">bad</span>”, while one that doesn't is |
|
759 “<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 |
|
760 directory is synced (usually the tip) already exhibits the |
|
761 problem introduced by the buggy change, so we'll mark it as |
|
762 “<span class="quote">bad</span>”.</p><pre id="id396047" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --bad</code></strong> |
|
763 </pre><p id="x_141"><a name="x_141"></a>Our next task is to nominate a changeset that we know |
|
764 <span class="emphasis"><em>doesn't</em></span> have the bug; the <span class="command"><strong>hg bisect</strong></span> command will |
|
765 “<span class="quote">bracket</span>” its search between the first pair of |
|
766 good and bad changesets. In our case, we know that revision |
|
767 10 didn't have the bug. (I'll have more words about choosing |
|
768 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> |
|
769 |
|
770 Testing changeset 22:b8789808fc48 (24 changesets remaining, ~4 tests) |
|
771 0 files updated, 0 files merged, 12 files removed, 0 files unresolved |
|
772 </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 |
|
773 consider before it can identify the one that introduced |
|
774 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 |
|
775 changeset to test, and told us which changeset it's |
|
776 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 |
|
777 <span class="command"><strong>grep</strong></span> command to see if our |
|
778 “<span class="quote">bad</span>” file is present in the working directory. |
|
779 If it is, this revision is bad; if not, this revision is good. |
|
780 |
|
781 </p><pre id="id395911" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>if grep -q 'i have a gub' *</code></strong> |
|
782 <code class="prompt">></code> <strong class="userinput"><code>then</code></strong> |
|
783 |
|
784 <code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong> |
|
785 <code class="prompt">></code> <strong class="userinput"><code>else</code></strong> |
|
786 <code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong> |
|
787 <code class="prompt">></code> <strong class="userinput"><code>fi</code></strong> |
|
788 <code class="prompt">$</code> <strong class="userinput"><code>echo this revision is $result</code></strong> |
|
789 |
|
790 this revision is bad |
|
791 <code class="prompt">$</code> <strong class="userinput"><code>hg bisect --$result</code></strong> |
|
792 Testing changeset 16:e61fdddff53e (12 changesets remaining, ~3 tests) |
|
793 0 files updated, 0 files merged, 6 files removed, 0 files unresolved |
|
794 </pre><p> |
|
795 |
|
796 </p><p id="x_146"><a name="x_146"></a>This test looks like a perfect candidate for automation, |
|
797 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> |
|
798 <code class="prompt">></code> <strong class="userinput"><code> if grep -q 'i have a gub' *</code></strong> |
|
799 |
|
800 <code class="prompt">></code> <strong class="userinput"><code> then</code></strong> |
|
801 <code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong> |
|
802 <code class="prompt">></code> <strong class="userinput"><code> else</code></strong> |
|
803 <code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong> |
|
804 <code class="prompt">></code> <strong class="userinput"><code> fi</code></strong> |
|
805 |
|
806 <code class="prompt">></code> <strong class="userinput"><code> echo this revision is $result</code></strong> |
|
807 <code class="prompt">></code> <strong class="userinput"><code> hg bisect --$result</code></strong> |
|
808 <code class="prompt">></code> <strong class="userinput"><code>}</code></strong> |
|
809 </pre><p id="x_147"><a name="x_147"></a>We can now run an entire test step with a single command, |
|
810 <code class="literal">mytest</code>.</p><pre id="id396403" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong> |
|
811 |
|
812 this revision is good |
|
813 Testing changeset 19:706df39b003b (6 changesets remaining, ~2 tests) |
|
814 3 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
815 </pre><p id="x_148"><a name="x_148"></a>A few more invocations of our canned test step command, |
|
816 and we're done.</p><pre id="id396344" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong> |
|
817 this revision is good |
|
818 Testing changeset 20:bf7ea9a054e6 (3 changesets remaining, ~1 tests) |
|
819 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
820 <code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong> |
|
821 this revision is good |
|
822 Testing changeset 21:921391dd45c1 (2 changesets remaining, ~1 tests) |
|
823 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
824 <code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong> |
|
825 this revision is good |
|
826 The first bad revision is: |
|
827 changeset: 22:b8789808fc48 |
|
828 user: Bryan O'Sullivan <bos@serpentine.com> |
|
829 |
|
830 date: Tue May 05 06:55:14 2009 +0000 |
|
831 summary: buggy changeset |
|
832 |
|
833 </pre><p id="x_149"><a name="x_149"></a>Even though we had 40 changesets to search through, the |
|
834 <span class="command"><strong>hg bisect</strong></span> command let us find |
|
835 the changeset that introduced our “<span class="quote">bug</span>” with only |
|
836 five tests. Because the number of tests that the <span class="command"><strong>hg bisect</strong></span> command performs grows |
|
837 logarithmically with the number of changesets to search, the |
|
838 advantage that it has over the “<span class="quote">brute force</span>” |
|
839 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 |
|
840 bisect</strong></span> command in a repository, you can use the |
|
841 <span class="command"><strong>hg bisect --reset</strong></span> command to |
|
842 drop the information it was using to drive your search. The |
|
843 command doesn't use much space, so it doesn't matter if you |
|
844 forget to run this command. However, <span class="command"><strong>hg bisect</strong></span> won't let you start a new |
|
845 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> |
|
846 |
|
847 </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 |
|
848 requires that you correctly report the result of every test |
|
849 you perform. If you tell it that a test failed when it really |
|
850 succeeded, it <span class="emphasis"><em>might</em></span> be able to detect the |
|
851 inconsistency. If it can identify an inconsistency in your |
|
852 reports, it will tell you that a particular changeset is both |
|
853 good and bad. However, it can't do this perfectly; it's about |
|
854 as likely to report the wrong changeset as the source of the |
|
855 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 |
|
856 bisect</strong></span> command, I tried a few times to run my |
|
857 tests by hand, on the command line. This is an approach that |
|
858 I, at least, am not suited to. After a few tries, I found |
|
859 that I was making enough mistakes that I was having to restart |
|
860 my searches several times before finally getting correct |
|
861 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 |
|
862 even with simple searches on small repositories; if the |
|
863 problem you're looking for is more subtle, or the number of |
|
864 tests that <span class="command"><strong>hg bisect</strong></span> must |
|
865 perform increases, the likelihood of operator error ruining |
|
866 the search is much higher. Once I started automating my |
|
867 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> |
|
868 |
|
869 command tests for the symptom, and the <code class="literal">if</code> |
|
870 statement takes the result of this check and ensures that we |
|
871 always feed the same input to the <span class="command"><strong>hg |
|
872 bisect</strong></span> command. The <code class="literal">mytest</code> |
|
873 function marries these together in a reproducible way, so that |
|
874 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 |
|
875 bisect</strong></span> search is only as good as the input you |
|
876 give it, don't take the changeset it reports as the absolute |
|
877 truth. A simple way to cross-check its report is to manually |
|
878 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 |
|
879 revision. Your test should still report this as |
|
880 bad.</p></li><li><p id="x_154"><a name="x_154"></a>The parent of that changeset (either parent, |
|
881 if it's a merge). Your test should report this changeset |
|
882 as good.</p></li><li><p id="x_155"><a name="x_155"></a>A child of that changeset. Your test should |
|
883 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 |
|
884 disrupted by the presence of another. For example, let's say |
|
885 your software crashes at revision 100, and worked correctly at |
|
886 revision 50. Unknown to you, someone else introduced a |
|
887 different crashing bug at revision 60, and fixed it at |
|
888 revision 80. This could distort your results in one of |
|
889 several ways.</p><p id="x_157"><a name="x_157"></a>It is possible that this other bug completely |
|
890 “<span class="quote">masks</span>” yours, which is to say that it occurs |
|
891 before your bug has a chance to manifest itself. If you can't |
|
892 avoid that other bug (for example, it prevents your project |
|
893 from building), and so can't tell whether your bug is present |
|
894 in a particular changeset, the <span class="command"><strong>hg |
|
895 bisect</strong></span> command cannot help you directly. Instead, |
|
896 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 |
|
897 presence is not specific enough. If you check for “<span class="quote">my |
|
898 program crashes</span>”, then both your crashing bug and an |
|
899 unrelated crashing bug that masks it will look like the same |
|
900 thing, and mislead <span class="command"><strong>hg |
|
901 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 |
|
902 test a revision because your project was in a broken and hence |
|
903 untestable state at that revision, perhaps because someone |
|
904 checked in a change that prevented the project from |
|
905 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 |
|
906 “<span class="quote">bad</span>” changesets that will mark the end points of |
|
907 your search is often easy, but it bears a little discussion |
|
908 nevertheless. From the perspective of <span class="command"><strong>hg bisect</strong></span>, the “<span class="quote">newest</span>” |
|
909 changeset is conventionally “<span class="quote">bad</span>”, and the older |
|
910 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 |
|
911 “<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 |
|
912 testing changesets at random. Just remember to eliminate |
|
913 contenders that can't possibly exhibit the bug (perhaps |
|
914 because the feature with the bug isn't present yet) and those |
|
915 where another problem masks the bug (as I discussed |
|
916 above).</p><p id="x_15c"><a name="x_15c"></a>Even if you end up “<span class="quote">early</span>” by thousands of |
|
917 changesets or months of history, you will only add a handful |
|
918 of tests to the total number that <span class="command"><strong>hg |
|
919 bisect</strong></span> must perform, thanks to its logarithmic |
|
920 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. |
|
921 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"> |
|
922 var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); |
|
923 document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); |
|
924 </script><script type="text/javascript"> |
|
925 try { |
|
926 var pageTracker = _gat._getTracker("UA-1805907-5"); |
|
927 pageTracker._trackPageview(); |
|
928 } catch(err) {}</script></body></html> |
|
929 |
|