hgbook

diff en/undo.tex @ 124:c9aad709bd3a

Document the backout command.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Dec 26 13:08:20 2006 -0800 (2006-12-26)
parents f954c6f6eaa1
children 8f8a1ad9627a
line diff
     1.1 --- a/en/undo.tex	Tue Dec 26 09:59:12 2006 -0800
     1.2 +++ b/en/undo.tex	Tue Dec 26 13:08:20 2006 -0800
     1.3 @@ -115,11 +115,12 @@
     1.4  \section{Reverting the mistaken change}
     1.5  
     1.6  If you make a modification to a file, and decide that you really
     1.7 -didn't want to change the file at all, the \hgcmd{revert} command is
     1.8 -the one you'll need.  It looks at the changeset that's the parent of
     1.9 -the working directory, and restores the contents of the file to their
    1.10 -state as of that changeset.  (That's a long-winded way of saying that,
    1.11 -in the normal case, it undoes your modifications.)
    1.12 +didn't want to change the file at all, and you haven't yet committed
    1.13 +your changes, the \hgcmd{revert} command is the one you'll need.  It
    1.14 +looks at the changeset that's the parent of the working directory, and
    1.15 +restores the contents of the file to their state as of that changeset.
    1.16 +(That's a long-winded way of saying that, in the normal case, it
    1.17 +undoes your modifications.)
    1.18  
    1.19  Let's illustrate how the \hgcmd{revert} command works with yet another
    1.20  small example.  We'll begin by modifying a file that Mercurial is
    1.21 @@ -131,6 +132,21 @@
    1.22  by saving our modified file with a \filename{.orig} extension.
    1.23  \interaction{daily.revert.status}
    1.24  
    1.25 +Here is a summary of the cases that the \hgcmd{revert} command can
    1.26 +deal with.  We will describe each of these in more detail in the
    1.27 +section that follows.
    1.28 +\begin{itemize}
    1.29 +\item If you modify a file, it will restore the file to its unmodified
    1.30 +  state.
    1.31 +\item If you \hgcmd{add} a file, it will undo the ``added'' state of
    1.32 +  the file, but leave the file itself untouched.
    1.33 +\item If you delete a file without telling Mercurial, it will restore
    1.34 +  the file to its unmodified contents.
    1.35 +\item If you use the \hgcmd{remove} command to remove a file, it will
    1.36 +  undo the ``removed'' state of the file, and restore the file to its
    1.37 +  unmodified contents.
    1.38 +\end{itemize}
    1.39 +
    1.40  \subsection{File management errors}
    1.41  \label{sec:undo:mgmt}
    1.42  
    1.43 @@ -183,6 +199,203 @@
    1.44  These fiddly aspects of reverting a rename arguably constitute a small
    1.45  bug in Mercurial.
    1.46  
    1.47 +\section{Dealing with committed changes}
    1.48 +
    1.49 +Consider a case where you have committed a change $a$, and another
    1.50 +change $b$ on top of it; you then realise that change $a$ was
    1.51 +incorrect.  Mercurial lets you ``back out'' an entire changeset
    1.52 +automatically, and building blocks that let you reverse part of a
    1.53 +changeset by hand.
    1.54 +
    1.55 +\subsection{Backing out a changeset}
    1.56 +
    1.57 +The \hgcmd{backout} command lets you ``undo'' the effects of an entire
    1.58 +changeset in an automated fashion.  Because Mercurial's history is
    1.59 +immutable, this command \emph{does not} get rid of the changeset you
    1.60 +want to undo.  Instead, it creates a new changeset that
    1.61 +\emph{reverses} the effect of the to-be-undone changeset.
    1.62 +
    1.63 +The operation of the \hgcmd{backout} command is a little intricate, so
    1.64 +let's illustrate it with some examples.  First, we'll create a
    1.65 +repository with some simple changes.
    1.66 +\interaction{backout.init}
    1.67 +
    1.68 +The \hgcmd{backout} command takes a single changeset ID as its
    1.69 +argument; this is the changeset to back out.  Normally,
    1.70 +\hgcmd{backout} will drop you into a text editor to write a commit
    1.71 +message, so you can record why you're backing the change out.  In this
    1.72 +example, we provide a commit message on the command line using the
    1.73 +\hgopt{backout}{-m} option.
    1.74 +
    1.75 +\subsection{Backing out the tip changeset}
    1.76 +
    1.77 +We're going to start by backing out the last changeset we committed.
    1.78 +\interaction{backout.simple}
    1.79 +You can see that the second line from \filename{myfile} is no longer
    1.80 +present.  Taking a look at the output of \hgcmd{log} gives us an idea
    1.81 +of what the \hgcmd{backout} command has done.
    1.82 +\interaction{backout.simple.log}
    1.83 +Notice that the new changeset that \hgcmd{backout} has created is a
    1.84 +child of the changeset we backed out.  It's easier to see this in
    1.85 +figure~\ref{fig:undo:backout}, which presents a graphical view of the
    1.86 +change history.  As you can see, the history is nice and linear.
    1.87 +
    1.88 +\begin{figure}[htb]
    1.89 +  \centering
    1.90 +  \grafix{undo-simple}
    1.91 +  \caption{Backing out a change using the \hgcmd{backout} command}
    1.92 +  \label{fig:undo:backout}
    1.93 +\end{figure}
    1.94 +
    1.95 +\subsection{Backing out a non-tip change}
    1.96 +
    1.97 +If you want to back out a change other than the last one you
    1.98 +committed, pass the \hgopt{backout}{--merge} option to the
    1.99 +\hgcmd{backout} command.
   1.100 +\interaction{backout.non-tip.clone}
   1.101 +This makes backing out any changeset a ``one-shot'' operation that's
   1.102 +usually simple and fast.
   1.103 +\interaction{backout.non-tip.backout}
   1.104 +
   1.105 +If you take a look at the contents of \filename{myfile} after the
   1.106 +backout finishes, you'll see that the first and third changes are
   1.107 +present, but not the second.
   1.108 +\interaction{backout.non-tip.cat}
   1.109 +
   1.110 +As the graphical history in figure~\ref{fig:undo:backout-non-tip}
   1.111 +illustrates, Mercurial actually commits \emph{two} changes in this
   1.112 +kind of situation (the box-shaped nodes are the ones that Mercurial
   1.113 +commits automatically).  Before Mercurial begins the backout process,
   1.114 +it first remembers what the current parent of the working directory
   1.115 +is.  It then backs out the target changeset, and commits that as a
   1.116 +changeset.  Finally, it merges back to the previous parent of the
   1.117 +working directory, and commits the result of the merge.
   1.118 +
   1.119 +\begin{figure}[htb]
   1.120 +  \centering
   1.121 +  \grafix{undo-non-tip}
   1.122 +  \caption{Automated backout of a non-tip change using the \hgcmd{backout} command}
   1.123 +  \label{fig:undo:backout-non-tip}
   1.124 +\end{figure}
   1.125 +
   1.126 +The result is that you end up ``back where you were'', only with some
   1.127 +extra history that undoes the effect of the changeset you wanted to
   1.128 +back out.
   1.129 +
   1.130 +\subsubsection{Always use the \hgopt{backout}{--merge} option}
   1.131 +
   1.132 +In fact, since the \hgopt{backout}{--merge} option will do the ``right
   1.133 +thing'' whether or not the changeset you're backing out is the tip
   1.134 +(i.e.~it won't try to merge if it's backing out the tip, since there's
   1.135 +no need), you should \emph{always} use this option when you run the
   1.136 +\hgcmd{backout} command.
   1.137 +
   1.138 +\subsection{Gaining more control of the backout process}
   1.139 +
   1.140 +While I've recommended that you always use the
   1.141 +\hgopt{backout}{--merge} option when backing out a change, the
   1.142 +\hgcmd{backout} command lets you decide how to merge a backout
   1.143 +changeset.  Taking control of the backout process by hand is something
   1.144 +you will rarely need to do, but it can be useful to understand what
   1.145 +the \hgcmd{backout} command is doing for you automatically.  To
   1.146 +illustrate this, let's clone our first repository, but omit the
   1.147 +backout change that it contains.
   1.148 +
   1.149 +\interaction{backout.manual.clone}
   1.150 +As with our earlier example, We'll commit a third changeset, then back
   1.151 +out its parent, and see what happens.
   1.152 +\interaction{backout.manual.backout} 
   1.153 +Our new changeset is again a descendant of the changeset we backout
   1.154 +out; it's thus a new head, \emph{not} a descendant of the changeset
   1.155 +that was the tip.  The \hgcmd{backout} command was quite explicit in
   1.156 +telling us this.
   1.157 +\interaction{backout.manual.log}
   1.158 +
   1.159 +Again, it's easier to see what has happened by looking at a graph of
   1.160 +the revision history, in figure~\ref{fig:undo:backout-manual}.  This
   1.161 +makes it clear that when we use \hgcmd{backout} to back out a change
   1.162 +other than the tip, Mercurial adds a new head to the repository (the
   1.163 +change it committed is box-shaped).
   1.164 +
   1.165 +\begin{figure}[htb]
   1.166 +  \centering
   1.167 +  \grafix{undo-manual}
   1.168 +  \caption{Backing out a change using the \hgcmd{backout} command}
   1.169 +  \label{fig:undo:backout-manual}
   1.170 +\end{figure}
   1.171 +
   1.172 +After the \hgcmd{backout} command has completed, it leaves the new
   1.173 +``backout'' changeset as the parent of the working directory.
   1.174 +\interaction{backout.manual.parents}
   1.175 +Now we have two isolated sets of changes.
   1.176 +\interaction{backout.manual.heads}
   1.177 +
   1.178 +Let's think about what we expect to see as the contents of
   1.179 +\filename{myfile} now.  The first change should be present, because
   1.180 +we've never backed it out.  The second change should be missing, as
   1.181 +that's the change we backed out.  Since the history graph shows the
   1.182 +third change as a separate head, we \emph{don't} expect to see the
   1.183 +third change present in \filename{myfile}.
   1.184 +\interaction{backout.manual.cat}
   1.185 +To get the third change back into the file, we just do a normal merge
   1.186 +of our two heads.
   1.187 +\interaction{backout.manual.merge}
   1.188 +Afterwards, the graphical history of our repository looks like
   1.189 +figure~\ref{fig:undo:backout-manual-merge}.
   1.190 +
   1.191 +\begin{figure}[htb]
   1.192 +  \centering
   1.193 +  \grafix{undo-manual-merge}
   1.194 +  \caption{Manually merging a backout change}
   1.195 +  \label{fig:undo:backout-manual-merge}
   1.196 +\end{figure}
   1.197 +
   1.198 +\subsection{A rationale}
   1.199 +
   1.200 +Here's a brief description of how the \hgcmd{backout} command works.
   1.201 +\begin{enumerate}
   1.202 +\item It ensures that the working directory is ``clean'', i.e.~that
   1.203 +  the output of \hgcmd{status} would be empty.
   1.204 +\item It remembers the current parent of the working directory.  Let's
   1.205 +  call this changeset \texttt{orig}
   1.206 +\item It does the equivalent of a \hgcmd{update} to sync the working
   1.207 +  directory to the changeset you want to back out.  Let's call this
   1.208 +  changeset \texttt{backout}
   1.209 +\item It finds the parent of that changeset.  Let's call that
   1.210 +  changeset \texttt{parent}.
   1.211 +\item For each file that the \texttt{backout} changeset affected, it
   1.212 +  does the equivalent of a \hgcmdargs{revert}{-r parent} on that file,
   1.213 +  to restore it to the contents it had before that changeset was
   1.214 +  committed.
   1.215 +\item It commits the result as a new changeset.  This changeset has
   1.216 +  \texttt{backout} as its parent.
   1.217 +\item If you specify \hgopt{backout}{--merge} on the command line, it
   1.218 +  merges with \texttt{orig}, and commits the result of the merge.
   1.219 +\end{enumerate}
   1.220 +
   1.221 +An alternative way to implement the \hgcmd{backout} command would be
   1.222 +to \hgcmd{export} the to-be-backed-out changeset as a diff, then use
   1.223 +the \cmdopt{patch}{--reverse} option to the \command{patch} command to
   1.224 +reverse the effect of the change without fiddling with the working
   1.225 +directory.  This sounds much simpler, but it would not work nearly as
   1.226 +well.
   1.227 +
   1.228 +The reason that \hgcmd{backout} does an update, a commit, a merge, and
   1.229 +another commit is to give the merge machinery the best chance to do a
   1.230 +good job when dealing with all the changes \emph{between} the change
   1.231 +you're backing out and the current tip.  
   1.232 +
   1.233 +If you're backing out a changeset that's~100 revisions back in your
   1.234 +project's history, the chances that the \command{patch} command will
   1.235 +be able to apply a reverse diff cleanly are not good, because
   1.236 +intervening changes are likely to have ``broken the context'' that
   1.237 +\command{patch} uses to determine whether it can apply a patch (if
   1.238 +this sounds like gibberish, see \section{sec:mq:patch} for a
   1.239 +discussion of the \command{patch} command).  Also, Mercurial's merge
   1.240 +machinery will handle files and directories being renamed, permission
   1.241 +changes, and modifications to binary files, none of which
   1.242 +\command{patch} can deal with.
   1.243 +
   1.244  %%% Local Variables: 
   1.245  %%% mode: latex
   1.246  %%% TeX-master: "00book"