hgbook

view en/undo.tex @ 125:8f8a1ad9627a

Fix silly typo.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Dec 26 14:06:41 2006 -0800 (2006-12-26)
parents c9aad709bd3a
children fa3c43dd3a1e
line source
1 \chapter{Finding and fixing your mistakes}
2 \label{chap:undo}
4 To err might be human, but to really handle the consequences well
5 takes a top-notch revision control system. In this chapter, we'll
6 discuss some of the techniques you can use when you find that a
7 problem has crept into your project. Mercurial has some highly
8 capable features that will help you to isolate the sources of
9 problems, and to handle them appropriately.
11 \section{Erasing local history}
13 \subsection{The accidental commit}
15 I have the occasional but persistent problem of typing rather more
16 quickly than I can think, which sometimes results in me committing a
17 changeset that is either incomplete or plain wrong. In my case, the
18 usual kind of incomplete changeset is one in which I've created a new
19 source file, but forgotten to \hgcmd{add} it. A ``plain wrong''
20 changeset is not as common, but no less annoying.
22 \subsection{Rolling back a transaction}
24 In section~\ref{sec:concepts:txn}, I mentioned that Mercurial treats
25 each modification of a repository as a \emph{transaction}. Every time
26 you commit a changeset or pull changes from another repository,
27 Mercurial remembers what you did. You can undo, or \emph{roll back},
28 exactly one of these actions using the \hgcmd{rollback} command.
30 Here's a mistake that I often find myself making: committing a change
31 in which I've created a new file, but forgotten to \hgcmd{add} it.
32 \interaction{rollback.commit}
33 Looking at the output of \hgcmd{status} after the commit immediately
34 confirms the error.
35 \interaction{rollback.status}
36 The commit captured the changes to the file \filename{a}, but not the
37 new file \filename{b}. If I were to push this changeset to a
38 repository that I shared with a colleague, the chances are high that
39 something in \filename{a} would refer to \filename{b}, which would not
40 be present in their repository when they pulled my changes. I would
41 thus become the object of some indignation.
43 However, luck is with me---I've caught my error before I pushed the
44 changeset. I use the \hgcmd{rollback} command, and Mercurial makes
45 that last changeset vanish.
46 \interaction{rollback.rollback}
47 Notice that the changeset is no longer present in the repository's
48 history, and the working directory once again thinks that the file
49 \filename{a} is modified. The commit and rollback have left the
50 working directory exactly as it was prior to the commit; the changeset
51 has been completely erased. I can now safely \hgcmd{add} the file
52 \filename{b}, and rerun my commit.
53 \interaction{rollback.add}
55 \subsection{The erroneous pull}
57 It's common practice with Mercurial to maintain separate development
58 branches of a project in different repositories. Your development
59 team might have one shared repository for your project's ``0.9''
60 release, and another, containing different changes, for the ``1.0''
61 release.
63 Given this, you can imagine that the consequences could be messy if
64 you had a local ``0.9'' repository, and accidentally pulled changes
65 from the shared ``1.0'' repository into it. At worst, you could be
66 paying insufficient attention, and push those changes into the shared
67 ``0.9'' tree, confusing your entire team (but don't worry, we'll
68 return to this horror scenario later). However, it's more likely that
69 you'll notice immediately, because Mercurial will display the URL it's
70 pulling from, or you will see it pull a suspiciously large number of
71 changes into the repository.
73 The \hgcmd{rollback} command will work nicely to expunge all of the
74 changesets that you just pulled. Mercurial groups all changes from
75 one \hgcmd{pull} into a single transaction, so one \hgcmd{rollback} is
76 all you need to undo this mistake.
78 \subsection{Rolling back is useless once you've pushed}
80 The value of the \hgcmd{rollback} command drops to zero once you've
81 pushed your changes to another repository. Rolling back a change
82 makes it disappear entirely, but \emph{only} in the repository in
83 which you perform the \hgcmd{rollback}. Because a rollback eliminates
84 history, there's no way for the disappearance of a change to propagate
85 between repositories.
87 If you've pushed a change to another repository---particularly if it's
88 a shared repository---it has essentially ``escaped into the wild,''
89 and you'll have to recover from your mistake in a different way. What
90 will happen if you push a changeset somewhere, then roll it back, then
91 pull from the repository you pushed to, is that the changeset will
92 reappear in your repository.
94 (If you absolutely know for sure that the change you want to roll back
95 is the most recent change in the repository that you pushed to,
96 \emph{and} you know that nobody else could have pulled it from that
97 repository, you can roll back the changeset there, too, but you really
98 should really not rely on this working reliably. If you do this,
99 sooner or later a change really will make it into a repository that
100 you don't directly control (or have forgotten about), and come back to
101 bite you.)
103 \subsection{You can only roll back once}
105 Mercurial stores exactly one transaction in its transaction log; that
106 transaction is the most recent one that occurred in the repository.
107 This means that you can only roll back one transaction. If you expect
108 to be able to roll back one transaction, then its predecessor, this is
109 not the behaviour you will get.
110 \interaction{rollback.twice}
111 Once you've rolled back one transaction in a repository, you can't
112 roll back again in that repository until you perform another commit or
113 pull.
115 \section{Reverting the mistaken change}
117 If you make a modification to a file, and decide that you really
118 didn't want to change the file at all, and you haven't yet committed
119 your changes, the \hgcmd{revert} command is the one you'll need. It
120 looks at the changeset that's the parent of the working directory, and
121 restores the contents of the file to their state as of that changeset.
122 (That's a long-winded way of saying that, in the normal case, it
123 undoes your modifications.)
125 Let's illustrate how the \hgcmd{revert} command works with yet another
126 small example. We'll begin by modifying a file that Mercurial is
127 already tracking.
128 \interaction{daily.revert.modify}
129 If we don't want that change, we can simply \hgcmd{revert} the file.
130 \interaction{daily.revert.unmodify}
131 The \hgcmd{revert} command provides us with an extra degree of safety
132 by saving our modified file with a \filename{.orig} extension.
133 \interaction{daily.revert.status}
135 Here is a summary of the cases that the \hgcmd{revert} command can
136 deal with. We will describe each of these in more detail in the
137 section that follows.
138 \begin{itemize}
139 \item If you modify a file, it will restore the file to its unmodified
140 state.
141 \item If you \hgcmd{add} a file, it will undo the ``added'' state of
142 the file, but leave the file itself untouched.
143 \item If you delete a file without telling Mercurial, it will restore
144 the file to its unmodified contents.
145 \item If you use the \hgcmd{remove} command to remove a file, it will
146 undo the ``removed'' state of the file, and restore the file to its
147 unmodified contents.
148 \end{itemize}
150 \subsection{File management errors}
151 \label{sec:undo:mgmt}
153 The \hgcmd{revert} command is useful for more than just modified
154 files. It lets you reverse the results of all of Mercurial's file
155 management commands---\hgcmd{add}, \hgcmd{remove}, and so on.
157 If you \hgcmd{add} a file, then decide that in fact you don't want
158 Mercurial to track it, use \hgcmd{revert} to undo the add. Don't
159 worry; Mercurial will not modify the file in any way. It will just
160 ``unmark'' the file.
161 \interaction{daily.revert.add}
163 Similarly, if you ask Mercurial to \hgcmd{remove} a file, you can use
164 \hgcmd{revert} to restore it to the contents it had as of the parent
165 of the working directory.
166 \interaction{daily.revert.remove}
167 This works just as well for a file that you deleted by hand, without
168 telling Mercurial (recall that in Mercurial terminology, this kind of
169 file is called ``missing'').
170 \interaction{daily.revert.missing}
172 If you revert a \hgcmd{copy}, the copied-to file remains in your
173 working directory afterwards, untracked. Since a copy doesn't affect
174 the copied-from file in any way, Mercurial doesn't do anything with
175 the copied-from file.
176 \interaction{daily.revert.copy}
178 \subsubsection{A slightly special case: reverting a rename}
180 If you \hgcmd{rename} a file, there is one small detail that
181 you should remember. When you \hgcmd{revert} a rename, it's not
182 enough to provide the name of the renamed-to file, as you can see
183 here.
184 \interaction{daily.revert.rename}
185 As you can see from the output of \hgcmd{status}, the renamed-to file
186 is no longer identified as added, but the renamed-\emph{from} file is
187 still removed! This is counter-intuitive (at least to me), but at
188 least it's easy to deal with.
189 \interaction{daily.revert.rename-orig}
190 So remember, to revert a \hgcmd{rename}, you must provide \emph{both}
191 the source and destination names.
193 (By the way, if you rename a file, then modify the renamed-to file,
194 then revert both components of the rename, when Mercurial restores the
195 file that was removed as part of the rename, it will be unmodified.
196 If you need the modifications in the renamed-to file to show up in the
197 renamed-from file, don't forget to copy them over.)
199 These fiddly aspects of reverting a rename arguably constitute a small
200 bug in Mercurial.
202 \section{Dealing with committed changes}
204 Consider a case where you have committed a change $a$, and another
205 change $b$ on top of it; you then realise that change $a$ was
206 incorrect. Mercurial lets you ``back out'' an entire changeset
207 automatically, and building blocks that let you reverse part of a
208 changeset by hand.
210 \subsection{Backing out a changeset}
212 The \hgcmd{backout} command lets you ``undo'' the effects of an entire
213 changeset in an automated fashion. Because Mercurial's history is
214 immutable, this command \emph{does not} get rid of the changeset you
215 want to undo. Instead, it creates a new changeset that
216 \emph{reverses} the effect of the to-be-undone changeset.
218 The operation of the \hgcmd{backout} command is a little intricate, so
219 let's illustrate it with some examples. First, we'll create a
220 repository with some simple changes.
221 \interaction{backout.init}
223 The \hgcmd{backout} command takes a single changeset ID as its
224 argument; this is the changeset to back out. Normally,
225 \hgcmd{backout} will drop you into a text editor to write a commit
226 message, so you can record why you're backing the change out. In this
227 example, we provide a commit message on the command line using the
228 \hgopt{backout}{-m} option.
230 \subsection{Backing out the tip changeset}
232 We're going to start by backing out the last changeset we committed.
233 \interaction{backout.simple}
234 You can see that the second line from \filename{myfile} is no longer
235 present. Taking a look at the output of \hgcmd{log} gives us an idea
236 of what the \hgcmd{backout} command has done.
237 \interaction{backout.simple.log}
238 Notice that the new changeset that \hgcmd{backout} has created is a
239 child of the changeset we backed out. It's easier to see this in
240 figure~\ref{fig:undo:backout}, which presents a graphical view of the
241 change history. As you can see, the history is nice and linear.
243 \begin{figure}[htb]
244 \centering
245 \grafix{undo-simple}
246 \caption{Backing out a change using the \hgcmd{backout} command}
247 \label{fig:undo:backout}
248 \end{figure}
250 \subsection{Backing out a non-tip change}
252 If you want to back out a change other than the last one you
253 committed, pass the \hgopt{backout}{--merge} option to the
254 \hgcmd{backout} command.
255 \interaction{backout.non-tip.clone}
256 This makes backing out any changeset a ``one-shot'' operation that's
257 usually simple and fast.
258 \interaction{backout.non-tip.backout}
260 If you take a look at the contents of \filename{myfile} after the
261 backout finishes, you'll see that the first and third changes are
262 present, but not the second.
263 \interaction{backout.non-tip.cat}
265 As the graphical history in figure~\ref{fig:undo:backout-non-tip}
266 illustrates, Mercurial actually commits \emph{two} changes in this
267 kind of situation (the box-shaped nodes are the ones that Mercurial
268 commits automatically). Before Mercurial begins the backout process,
269 it first remembers what the current parent of the working directory
270 is. It then backs out the target changeset, and commits that as a
271 changeset. Finally, it merges back to the previous parent of the
272 working directory, and commits the result of the merge.
274 \begin{figure}[htb]
275 \centering
276 \grafix{undo-non-tip}
277 \caption{Automated backout of a non-tip change using the \hgcmd{backout} command}
278 \label{fig:undo:backout-non-tip}
279 \end{figure}
281 The result is that you end up ``back where you were'', only with some
282 extra history that undoes the effect of the changeset you wanted to
283 back out.
285 \subsubsection{Always use the \hgopt{backout}{--merge} option}
287 In fact, since the \hgopt{backout}{--merge} option will do the ``right
288 thing'' whether or not the changeset you're backing out is the tip
289 (i.e.~it won't try to merge if it's backing out the tip, since there's
290 no need), you should \emph{always} use this option when you run the
291 \hgcmd{backout} command.
293 \subsection{Gaining more control of the backout process}
295 While I've recommended that you always use the
296 \hgopt{backout}{--merge} option when backing out a change, the
297 \hgcmd{backout} command lets you decide how to merge a backout
298 changeset. Taking control of the backout process by hand is something
299 you will rarely need to do, but it can be useful to understand what
300 the \hgcmd{backout} command is doing for you automatically. To
301 illustrate this, let's clone our first repository, but omit the
302 backout change that it contains.
304 \interaction{backout.manual.clone}
305 As with our earlier example, We'll commit a third changeset, then back
306 out its parent, and see what happens.
307 \interaction{backout.manual.backout}
308 Our new changeset is again a descendant of the changeset we backout
309 out; it's thus a new head, \emph{not} a descendant of the changeset
310 that was the tip. The \hgcmd{backout} command was quite explicit in
311 telling us this.
312 \interaction{backout.manual.log}
314 Again, it's easier to see what has happened by looking at a graph of
315 the revision history, in figure~\ref{fig:undo:backout-manual}. This
316 makes it clear that when we use \hgcmd{backout} to back out a change
317 other than the tip, Mercurial adds a new head to the repository (the
318 change it committed is box-shaped).
320 \begin{figure}[htb]
321 \centering
322 \grafix{undo-manual}
323 \caption{Backing out a change using the \hgcmd{backout} command}
324 \label{fig:undo:backout-manual}
325 \end{figure}
327 After the \hgcmd{backout} command has completed, it leaves the new
328 ``backout'' changeset as the parent of the working directory.
329 \interaction{backout.manual.parents}
330 Now we have two isolated sets of changes.
331 \interaction{backout.manual.heads}
333 Let's think about what we expect to see as the contents of
334 \filename{myfile} now. The first change should be present, because
335 we've never backed it out. The second change should be missing, as
336 that's the change we backed out. Since the history graph shows the
337 third change as a separate head, we \emph{don't} expect to see the
338 third change present in \filename{myfile}.
339 \interaction{backout.manual.cat}
340 To get the third change back into the file, we just do a normal merge
341 of our two heads.
342 \interaction{backout.manual.merge}
343 Afterwards, the graphical history of our repository looks like
344 figure~\ref{fig:undo:backout-manual-merge}.
346 \begin{figure}[htb]
347 \centering
348 \grafix{undo-manual-merge}
349 \caption{Manually merging a backout change}
350 \label{fig:undo:backout-manual-merge}
351 \end{figure}
353 \subsection{A rationale}
355 Here's a brief description of how the \hgcmd{backout} command works.
356 \begin{enumerate}
357 \item It ensures that the working directory is ``clean'', i.e.~that
358 the output of \hgcmd{status} would be empty.
359 \item It remembers the current parent of the working directory. Let's
360 call this changeset \texttt{orig}
361 \item It does the equivalent of a \hgcmd{update} to sync the working
362 directory to the changeset you want to back out. Let's call this
363 changeset \texttt{backout}
364 \item It finds the parent of that changeset. Let's call that
365 changeset \texttt{parent}.
366 \item For each file that the \texttt{backout} changeset affected, it
367 does the equivalent of a \hgcmdargs{revert}{-r parent} on that file,
368 to restore it to the contents it had before that changeset was
369 committed.
370 \item It commits the result as a new changeset. This changeset has
371 \texttt{backout} as its parent.
372 \item If you specify \hgopt{backout}{--merge} on the command line, it
373 merges with \texttt{orig}, and commits the result of the merge.
374 \end{enumerate}
376 An alternative way to implement the \hgcmd{backout} command would be
377 to \hgcmd{export} the to-be-backed-out changeset as a diff, then use
378 the \cmdopt{patch}{--reverse} option to the \command{patch} command to
379 reverse the effect of the change without fiddling with the working
380 directory. This sounds much simpler, but it would not work nearly as
381 well.
383 The reason that \hgcmd{backout} does an update, a commit, a merge, and
384 another commit is to give the merge machinery the best chance to do a
385 good job when dealing with all the changes \emph{between} the change
386 you're backing out and the current tip.
388 If you're backing out a changeset that's~100 revisions back in your
389 project's history, the chances that the \command{patch} command will
390 be able to apply a reverse diff cleanly are not good, because
391 intervening changes are likely to have ``broken the context'' that
392 \command{patch} uses to determine whether it can apply a patch (if
393 this sounds like gibberish, see \ref{sec:mq:patch} for a
394 discussion of the \command{patch} command). Also, Mercurial's merge
395 machinery will handle files and directories being renamed, permission
396 changes, and modifications to binary files, none of which
397 \command{patch} can deal with.
399 %%% Local Variables:
400 %%% mode: latex
401 %%% TeX-master: "00book"
402 %%% End: