hgbook
changeset 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 |
files | en/00book.tex en/Makefile en/examples/backout en/examples/run-example en/undo-manual-merge.dot en/undo-manual.dot en/undo-non-tip.dot en/undo-simple.dot en/undo.tex |
line diff
1.1 --- a/en/00book.tex Tue Dec 26 09:59:12 2006 -0800 1.2 +++ b/en/00book.tex Tue Dec 26 13:08:20 2006 -0800 1.3 @@ -41,6 +41,7 @@ 1.4 \include{tour-merge} 1.5 \include{concepts} 1.6 \include{daily} 1.7 +\include{undo} 1.8 \include{hook} 1.9 \include{template} 1.10 \include{mq}
2.1 --- a/en/Makefile Tue Dec 26 09:59:12 2006 -0800 2.2 +++ b/en/Makefile Tue Dec 26 13:08:20 2006 -0800 2.3 @@ -33,15 +33,22 @@ 2.4 tour-merge-merge.svg \ 2.5 tour-merge-pull.svg \ 2.6 tour-merge-sep-repos.svg \ 2.7 + undo-manual.dot \ 2.8 + undo-manual-merge.dot \ 2.9 + undo-non-tip.dot \ 2.10 + undo-simple.dot \ 2.11 wdir.svg \ 2.12 wdir-after-commit.svg \ 2.13 wdir-branch.svg \ 2.14 wdir-merge.svg \ 2.15 wdir-pre-branch.svg 2.16 2.17 +image-dot := $(filter %.dot,$(image-sources)) 2.18 image-svg := $(filter %.svg,$(image-sources)) 2.19 +image-png := $(filter %.png,$(image-sources)) 2.20 2.21 example-sources := \ 2.22 + backout \ 2.23 daily.copy \ 2.24 daily.files \ 2.25 daily.rename \ 2.26 @@ -82,7 +89,9 @@ 2.27 if grep 'Reference.*undefined' $(@:.pdf=.log); then exit 1; fi 2.28 endef 2.29 2.30 -pdf/hgbook.pdf: $(sources) $(image-sources:%.svg=%.pdf) examples 2.31 +image-pdf := $(image-dot:%.dot=%.pdf) $(image-svg:%.svg=%.pdf) $(image-png) 2.32 + 2.33 +pdf/hgbook.pdf: $(sources) $(image-pdf) examples 2.34 $(call pdf) 2.35 2.36 html: html/onepage/hgbook.html html/split/hgbook.html 2.37 @@ -107,11 +116,13 @@ 2.38 perl -pi -e 's/�([0-7][0-9a-f]);/chr(hex($$1))/egi' $(dir $(1))/*.html 2.39 endef 2.40 2.41 -html/onepage/hgbook.html: $(sources) $(image-sources:%.svg=%.png) examples 2.42 +image-html := $(image-dot:%.dot=%.png) $(image-svg:%.svg=%.png) $(image-png) 2.43 + 2.44 +html/onepage/hgbook.html: $(sources) $(image-html) examples 2.45 $(call htlatex,$@,$<) 2.46 cp $(image-sources:%.svg=%.png) $(dir $@) 2.47 2.48 -html/split/hgbook.html: $(sources) $(image-sources:%.svg=%.png) examples 2.49 +html/split/hgbook.html: $(sources) $(image-html) examples 2.50 $(call htlatex,$@,$<,2) 2.51 cp $(image-sources:%.svg=%.png) $(dir $@) 2.52 2.53 @@ -136,6 +147,9 @@ 2.54 %.png: %.svg 2.55 inkscape -D -e $@ $< 2.56 2.57 +%.svg: %.dot 2.58 + dot -Tsvg -o $@ $< 2.59 + 2.60 # Produce eps & pdf for the pdf 2.61 2.62 %.pdf: %.eps 2.63 @@ -144,6 +158,9 @@ 2.64 %.eps: %.svg 2.65 inkscape -E $@ $< 2.66 2.67 +%.eps: %.dot 2.68 + dot -Tps -o $@ $< 2.69 + 2.70 examples: examples/.run 2.71 2.72 examples/.run: $(example-sources:%=examples/%.run) 2.73 @@ -157,6 +174,8 @@ 2.74 2.75 clean: 2.76 rm -rf beta html pdf \ 2.77 + $(image-dot:%.dot=%.pdf) \ 2.78 + $(image-dot:%.dot=%.png) \ 2.79 $(image-svg:%.svg=%.pdf) \ 2.80 $(image-svg:%.svg=%.png) \ 2.81 examples/*.{out,run} examples/.run build_id.tex
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/en/examples/backout Tue Dec 26 13:08:20 2006 -0800 3.3 @@ -0,0 +1,82 @@ 3.4 +#!/bin/bash 3.5 + 3.6 +# We have to fake the merges here, because they cause conflicts with 3.7 +# three-way command-line merge, and kdiff3 may not be available. 3.8 + 3.9 +export HGMERGE=$(mktemp) 3.10 +echo '#!/bin/sh' >> $HGMERGE 3.11 +echo 'echo first change > "$1"' >> $HGMERGE 3.12 +echo 'echo third change > "$1"' >> $HGMERGE 3.13 +chmod 700 $HGMERGE 3.14 + 3.15 +#$ name: init 3.16 + 3.17 +hg init myrepo 3.18 +cd myrepo 3.19 +echo first change >> myfile 3.20 +hg add myfile 3.21 +hg commit -m 'first change' 3.22 +echo second change >> myfile 3.23 +hg commit -m 'second change' 3.24 + 3.25 +#$ name: simple 3.26 + 3.27 +hg backout -m 'back out second change' tip 3.28 +cat myfile 3.29 + 3.30 +#$ name: simple.log 3.31 + 3.32 +hg log --style compact 3.33 + 3.34 +#$ name: non-tip.clone 3.35 + 3.36 +cd .. 3.37 +hg clone -r1 myrepo non-tip-repo 3.38 +cd non-tip-repo 3.39 + 3.40 +#$ name: non-tip.backout 3.41 + 3.42 +echo third change >> myfile 3.43 +hg commit -m 'third change' 3.44 +hg backout --merge -m 'back out second change' 1 3.45 + 3.46 +#$ name: non-tip.cat 3.47 +cat myfile 3.48 + 3.49 +#$ name: manual.clone 3.50 + 3.51 +cd .. 3.52 +hg clone -r1 myrepo newrepo 3.53 +cd newrepo 3.54 + 3.55 +#$ name: manual.backout 3.56 + 3.57 +echo third change >> myfile 3.58 +hg commit -m 'third change' 3.59 +hg backout -m 'back out second change' 1 3.60 + 3.61 +#$ name: manual.log 3.62 + 3.63 +hg log --style compact 3.64 + 3.65 +#$ name: manual.parents 3.66 + 3.67 +hg parents 3.68 + 3.69 +#$ name: manual.heads 3.70 + 3.71 +hg heads 3.72 + 3.73 +#$ name: manual.cat 3.74 + 3.75 +cat myfile 3.76 + 3.77 +#$ name: manual.merge 3.78 + 3.79 +hg merge 3.80 +hg commit -m 'merged backout with previous tip' 3.81 +cat myfile 3.82 + 3.83 +#$ name: 3.84 + 3.85 +rm $HGMERGE
4.1 --- a/en/examples/run-example Tue Dec 26 09:59:12 2006 -0800 4.2 +++ b/en/examples/run-example Tue Dec 26 13:08:20 2006 -0800 4.3 @@ -135,6 +135,7 @@ 4.4 print >> rcfp, 'PS2="%s"' % self.ps2 4.5 print >> rcfp, 'unset HISTFILE' 4.6 print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd() 4.7 + print >> rcfp, 'export HGMERGE=merge' 4.8 print >> rcfp, 'export LANG=C' 4.9 print >> rcfp, 'export LC_ALL=C' 4.10 print >> rcfp, 'export TZ=GMT'
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/en/undo-manual-merge.dot Tue Dec 26 13:08:20 2006 -0800 5.3 @@ -0,0 +1,8 @@ 5.4 +digraph undo_manual { 5.5 + "first change" -> "second change"; 5.6 + "second change" -> "third change"; 5.7 + backout [label="back out\nsecond change", shape=box]; 5.8 + "second change" -> backout; 5.9 + "third change" -> "manual\nmerge"; 5.10 + backout -> "manual\nmerge"; 5.11 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/en/undo-manual.dot Tue Dec 26 13:08:20 2006 -0800 6.3 @@ -0,0 +1,6 @@ 6.4 +digraph undo_manual { 6.5 + "first change" -> "second change"; 6.6 + "second change" -> "third change"; 6.7 + backout [label="back out\nsecond change", shape=box]; 6.8 + "second change" -> backout; 6.9 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/en/undo-non-tip.dot Tue Dec 26 13:08:20 2006 -0800 7.3 @@ -0,0 +1,9 @@ 7.4 +digraph undo_non_tip { 7.5 + "first change" -> "second change"; 7.6 + "second change" -> "third change"; 7.7 + backout [label="back out\nsecond change", shape=box]; 7.8 + "second change" -> backout; 7.9 + merge [label="automated\nmerge", shape=box]; 7.10 + "third change" -> merge; 7.11 + backout -> merge; 7.12 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/en/undo-simple.dot Tue Dec 26 13:08:20 2006 -0800 8.3 @@ -0,0 +1,4 @@ 8.4 +digraph undo_simple { 8.5 + "first change" -> "second change"; 8.6 + "second change" -> "back out\nsecond change"; 8.7 +}
9.1 --- a/en/undo.tex Tue Dec 26 09:59:12 2006 -0800 9.2 +++ b/en/undo.tex Tue Dec 26 13:08:20 2006 -0800 9.3 @@ -115,11 +115,12 @@ 9.4 \section{Reverting the mistaken change} 9.5 9.6 If you make a modification to a file, and decide that you really 9.7 -didn't want to change the file at all, the \hgcmd{revert} command is 9.8 -the one you'll need. It looks at the changeset that's the parent of 9.9 -the working directory, and restores the contents of the file to their 9.10 -state as of that changeset. (That's a long-winded way of saying that, 9.11 -in the normal case, it undoes your modifications.) 9.12 +didn't want to change the file at all, and you haven't yet committed 9.13 +your changes, the \hgcmd{revert} command is the one you'll need. It 9.14 +looks at the changeset that's the parent of the working directory, and 9.15 +restores the contents of the file to their state as of that changeset. 9.16 +(That's a long-winded way of saying that, in the normal case, it 9.17 +undoes your modifications.) 9.18 9.19 Let's illustrate how the \hgcmd{revert} command works with yet another 9.20 small example. We'll begin by modifying a file that Mercurial is 9.21 @@ -131,6 +132,21 @@ 9.22 by saving our modified file with a \filename{.orig} extension. 9.23 \interaction{daily.revert.status} 9.24 9.25 +Here is a summary of the cases that the \hgcmd{revert} command can 9.26 +deal with. We will describe each of these in more detail in the 9.27 +section that follows. 9.28 +\begin{itemize} 9.29 +\item If you modify a file, it will restore the file to its unmodified 9.30 + state. 9.31 +\item If you \hgcmd{add} a file, it will undo the ``added'' state of 9.32 + the file, but leave the file itself untouched. 9.33 +\item If you delete a file without telling Mercurial, it will restore 9.34 + the file to its unmodified contents. 9.35 +\item If you use the \hgcmd{remove} command to remove a file, it will 9.36 + undo the ``removed'' state of the file, and restore the file to its 9.37 + unmodified contents. 9.38 +\end{itemize} 9.39 + 9.40 \subsection{File management errors} 9.41 \label{sec:undo:mgmt} 9.42 9.43 @@ -183,6 +199,203 @@ 9.44 These fiddly aspects of reverting a rename arguably constitute a small 9.45 bug in Mercurial. 9.46 9.47 +\section{Dealing with committed changes} 9.48 + 9.49 +Consider a case where you have committed a change $a$, and another 9.50 +change $b$ on top of it; you then realise that change $a$ was 9.51 +incorrect. Mercurial lets you ``back out'' an entire changeset 9.52 +automatically, and building blocks that let you reverse part of a 9.53 +changeset by hand. 9.54 + 9.55 +\subsection{Backing out a changeset} 9.56 + 9.57 +The \hgcmd{backout} command lets you ``undo'' the effects of an entire 9.58 +changeset in an automated fashion. Because Mercurial's history is 9.59 +immutable, this command \emph{does not} get rid of the changeset you 9.60 +want to undo. Instead, it creates a new changeset that 9.61 +\emph{reverses} the effect of the to-be-undone changeset. 9.62 + 9.63 +The operation of the \hgcmd{backout} command is a little intricate, so 9.64 +let's illustrate it with some examples. First, we'll create a 9.65 +repository with some simple changes. 9.66 +\interaction{backout.init} 9.67 + 9.68 +The \hgcmd{backout} command takes a single changeset ID as its 9.69 +argument; this is the changeset to back out. Normally, 9.70 +\hgcmd{backout} will drop you into a text editor to write a commit 9.71 +message, so you can record why you're backing the change out. In this 9.72 +example, we provide a commit message on the command line using the 9.73 +\hgopt{backout}{-m} option. 9.74 + 9.75 +\subsection{Backing out the tip changeset} 9.76 + 9.77 +We're going to start by backing out the last changeset we committed. 9.78 +\interaction{backout.simple} 9.79 +You can see that the second line from \filename{myfile} is no longer 9.80 +present. Taking a look at the output of \hgcmd{log} gives us an idea 9.81 +of what the \hgcmd{backout} command has done. 9.82 +\interaction{backout.simple.log} 9.83 +Notice that the new changeset that \hgcmd{backout} has created is a 9.84 +child of the changeset we backed out. It's easier to see this in 9.85 +figure~\ref{fig:undo:backout}, which presents a graphical view of the 9.86 +change history. As you can see, the history is nice and linear. 9.87 + 9.88 +\begin{figure}[htb] 9.89 + \centering 9.90 + \grafix{undo-simple} 9.91 + \caption{Backing out a change using the \hgcmd{backout} command} 9.92 + \label{fig:undo:backout} 9.93 +\end{figure} 9.94 + 9.95 +\subsection{Backing out a non-tip change} 9.96 + 9.97 +If you want to back out a change other than the last one you 9.98 +committed, pass the \hgopt{backout}{--merge} option to the 9.99 +\hgcmd{backout} command. 9.100 +\interaction{backout.non-tip.clone} 9.101 +This makes backing out any changeset a ``one-shot'' operation that's 9.102 +usually simple and fast. 9.103 +\interaction{backout.non-tip.backout} 9.104 + 9.105 +If you take a look at the contents of \filename{myfile} after the 9.106 +backout finishes, you'll see that the first and third changes are 9.107 +present, but not the second. 9.108 +\interaction{backout.non-tip.cat} 9.109 + 9.110 +As the graphical history in figure~\ref{fig:undo:backout-non-tip} 9.111 +illustrates, Mercurial actually commits \emph{two} changes in this 9.112 +kind of situation (the box-shaped nodes are the ones that Mercurial 9.113 +commits automatically). Before Mercurial begins the backout process, 9.114 +it first remembers what the current parent of the working directory 9.115 +is. It then backs out the target changeset, and commits that as a 9.116 +changeset. Finally, it merges back to the previous parent of the 9.117 +working directory, and commits the result of the merge. 9.118 + 9.119 +\begin{figure}[htb] 9.120 + \centering 9.121 + \grafix{undo-non-tip} 9.122 + \caption{Automated backout of a non-tip change using the \hgcmd{backout} command} 9.123 + \label{fig:undo:backout-non-tip} 9.124 +\end{figure} 9.125 + 9.126 +The result is that you end up ``back where you were'', only with some 9.127 +extra history that undoes the effect of the changeset you wanted to 9.128 +back out. 9.129 + 9.130 +\subsubsection{Always use the \hgopt{backout}{--merge} option} 9.131 + 9.132 +In fact, since the \hgopt{backout}{--merge} option will do the ``right 9.133 +thing'' whether or not the changeset you're backing out is the tip 9.134 +(i.e.~it won't try to merge if it's backing out the tip, since there's 9.135 +no need), you should \emph{always} use this option when you run the 9.136 +\hgcmd{backout} command. 9.137 + 9.138 +\subsection{Gaining more control of the backout process} 9.139 + 9.140 +While I've recommended that you always use the 9.141 +\hgopt{backout}{--merge} option when backing out a change, the 9.142 +\hgcmd{backout} command lets you decide how to merge a backout 9.143 +changeset. Taking control of the backout process by hand is something 9.144 +you will rarely need to do, but it can be useful to understand what 9.145 +the \hgcmd{backout} command is doing for you automatically. To 9.146 +illustrate this, let's clone our first repository, but omit the 9.147 +backout change that it contains. 9.148 + 9.149 +\interaction{backout.manual.clone} 9.150 +As with our earlier example, We'll commit a third changeset, then back 9.151 +out its parent, and see what happens. 9.152 +\interaction{backout.manual.backout} 9.153 +Our new changeset is again a descendant of the changeset we backout 9.154 +out; it's thus a new head, \emph{not} a descendant of the changeset 9.155 +that was the tip. The \hgcmd{backout} command was quite explicit in 9.156 +telling us this. 9.157 +\interaction{backout.manual.log} 9.158 + 9.159 +Again, it's easier to see what has happened by looking at a graph of 9.160 +the revision history, in figure~\ref{fig:undo:backout-manual}. This 9.161 +makes it clear that when we use \hgcmd{backout} to back out a change 9.162 +other than the tip, Mercurial adds a new head to the repository (the 9.163 +change it committed is box-shaped). 9.164 + 9.165 +\begin{figure}[htb] 9.166 + \centering 9.167 + \grafix{undo-manual} 9.168 + \caption{Backing out a change using the \hgcmd{backout} command} 9.169 + \label{fig:undo:backout-manual} 9.170 +\end{figure} 9.171 + 9.172 +After the \hgcmd{backout} command has completed, it leaves the new 9.173 +``backout'' changeset as the parent of the working directory. 9.174 +\interaction{backout.manual.parents} 9.175 +Now we have two isolated sets of changes. 9.176 +\interaction{backout.manual.heads} 9.177 + 9.178 +Let's think about what we expect to see as the contents of 9.179 +\filename{myfile} now. The first change should be present, because 9.180 +we've never backed it out. The second change should be missing, as 9.181 +that's the change we backed out. Since the history graph shows the 9.182 +third change as a separate head, we \emph{don't} expect to see the 9.183 +third change present in \filename{myfile}. 9.184 +\interaction{backout.manual.cat} 9.185 +To get the third change back into the file, we just do a normal merge 9.186 +of our two heads. 9.187 +\interaction{backout.manual.merge} 9.188 +Afterwards, the graphical history of our repository looks like 9.189 +figure~\ref{fig:undo:backout-manual-merge}. 9.190 + 9.191 +\begin{figure}[htb] 9.192 + \centering 9.193 + \grafix{undo-manual-merge} 9.194 + \caption{Manually merging a backout change} 9.195 + \label{fig:undo:backout-manual-merge} 9.196 +\end{figure} 9.197 + 9.198 +\subsection{A rationale} 9.199 + 9.200 +Here's a brief description of how the \hgcmd{backout} command works. 9.201 +\begin{enumerate} 9.202 +\item It ensures that the working directory is ``clean'', i.e.~that 9.203 + the output of \hgcmd{status} would be empty. 9.204 +\item It remembers the current parent of the working directory. Let's 9.205 + call this changeset \texttt{orig} 9.206 +\item It does the equivalent of a \hgcmd{update} to sync the working 9.207 + directory to the changeset you want to back out. Let's call this 9.208 + changeset \texttt{backout} 9.209 +\item It finds the parent of that changeset. Let's call that 9.210 + changeset \texttt{parent}. 9.211 +\item For each file that the \texttt{backout} changeset affected, it 9.212 + does the equivalent of a \hgcmdargs{revert}{-r parent} on that file, 9.213 + to restore it to the contents it had before that changeset was 9.214 + committed. 9.215 +\item It commits the result as a new changeset. This changeset has 9.216 + \texttt{backout} as its parent. 9.217 +\item If you specify \hgopt{backout}{--merge} on the command line, it 9.218 + merges with \texttt{orig}, and commits the result of the merge. 9.219 +\end{enumerate} 9.220 + 9.221 +An alternative way to implement the \hgcmd{backout} command would be 9.222 +to \hgcmd{export} the to-be-backed-out changeset as a diff, then use 9.223 +the \cmdopt{patch}{--reverse} option to the \command{patch} command to 9.224 +reverse the effect of the change without fiddling with the working 9.225 +directory. This sounds much simpler, but it would not work nearly as 9.226 +well. 9.227 + 9.228 +The reason that \hgcmd{backout} does an update, a commit, a merge, and 9.229 +another commit is to give the merge machinery the best chance to do a 9.230 +good job when dealing with all the changes \emph{between} the change 9.231 +you're backing out and the current tip. 9.232 + 9.233 +If you're backing out a changeset that's~100 revisions back in your 9.234 +project's history, the chances that the \command{patch} command will 9.235 +be able to apply a reverse diff cleanly are not good, because 9.236 +intervening changes are likely to have ``broken the context'' that 9.237 +\command{patch} uses to determine whether it can apply a patch (if 9.238 +this sounds like gibberish, see \section{sec:mq:patch} for a 9.239 +discussion of the \command{patch} command). Also, Mercurial's merge 9.240 +machinery will handle files and directories being renamed, permission 9.241 +changes, and modifications to binary files, none of which 9.242 +\command{patch} can deal with. 9.243 + 9.244 %%% Local Variables: 9.245 %%% mode: latex 9.246 %%% TeX-master: "00book"