hgbook

view en/undo.tex @ 123:f954c6f6eaa1

Progress.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Dec 26 09:59:12 2006 -0800 (2006-12-26)
parents 3af28630fe8c
children c9aad709bd3a
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, the \hgcmd{revert} command is
119 the one you'll need. It looks at the changeset that's the parent of
120 the working directory, and restores the contents of the file to their
121 state as of that changeset. (That's a long-winded way of saying that,
122 in the normal case, it undoes your modifications.)
124 Let's illustrate how the \hgcmd{revert} command works with yet another
125 small example. We'll begin by modifying a file that Mercurial is
126 already tracking.
127 \interaction{daily.revert.modify}
128 If we don't want that change, we can simply \hgcmd{revert} the file.
129 \interaction{daily.revert.unmodify}
130 The \hgcmd{revert} command provides us with an extra degree of safety
131 by saving our modified file with a \filename{.orig} extension.
132 \interaction{daily.revert.status}
134 \subsection{File management errors}
135 \label{sec:undo:mgmt}
137 The \hgcmd{revert} command is useful for more than just modified
138 files. It lets you reverse the results of all of Mercurial's file
139 management commands---\hgcmd{add}, \hgcmd{remove}, and so on.
141 If you \hgcmd{add} a file, then decide that in fact you don't want
142 Mercurial to track it, use \hgcmd{revert} to undo the add. Don't
143 worry; Mercurial will not modify the file in any way. It will just
144 ``unmark'' the file.
145 \interaction{daily.revert.add}
147 Similarly, if you ask Mercurial to \hgcmd{remove} a file, you can use
148 \hgcmd{revert} to restore it to the contents it had as of the parent
149 of the working directory.
150 \interaction{daily.revert.remove}
151 This works just as well for a file that you deleted by hand, without
152 telling Mercurial (recall that in Mercurial terminology, this kind of
153 file is called ``missing'').
154 \interaction{daily.revert.missing}
156 If you revert a \hgcmd{copy}, the copied-to file remains in your
157 working directory afterwards, untracked. Since a copy doesn't affect
158 the copied-from file in any way, Mercurial doesn't do anything with
159 the copied-from file.
160 \interaction{daily.revert.copy}
162 \subsubsection{A slightly special case: reverting a rename}
164 If you \hgcmd{rename} a file, there is one small detail that
165 you should remember. When you \hgcmd{revert} a rename, it's not
166 enough to provide the name of the renamed-to file, as you can see
167 here.
168 \interaction{daily.revert.rename}
169 As you can see from the output of \hgcmd{status}, the renamed-to file
170 is no longer identified as added, but the renamed-\emph{from} file is
171 still removed! This is counter-intuitive (at least to me), but at
172 least it's easy to deal with.
173 \interaction{daily.revert.rename-orig}
174 So remember, to revert a \hgcmd{rename}, you must provide \emph{both}
175 the source and destination names.
177 (By the way, if you rename a file, then modify the renamed-to file,
178 then revert both components of the rename, when Mercurial restores the
179 file that was removed as part of the rename, it will be unmodified.
180 If you need the modifications in the renamed-to file to show up in the
181 renamed-from file, don't forget to copy them over.)
183 These fiddly aspects of reverting a rename arguably constitute a small
184 bug in Mercurial.
186 %%% Local Variables:
187 %%% mode: latex
188 %%% TeX-master: "00book"
189 %%% End: