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/&#x00([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"