hgbook

changeset 17:2668e15c76e9

MQ: write up patch rebasing.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Jul 04 15:00:18 2006 -0700 (2006-07-04)
parents 81454425eee9
children e6f4088ebe52
files en/99book.bib en/99defs.tex en/mq.tex
line diff
     1.1 --- a/en/99book.bib	Mon Jul 03 22:43:52 2006 -0700
     1.2 +++ b/en/99book.bib	Tue Jul 04 15:00:18 2006 -0700
     1.3 @@ -6,6 +6,15 @@
     1.4    note =         {\url{http://www.suse.de/~agruen/quilt.pdf}},
     1.5  }
     1.6  
     1.7 +@InProceedings{web:europython,
     1.8 +  author = 	 {Bryan O'Sullivan},
     1.9 +  title = 	 {Achieving High Performance in Mercurial},
    1.10 +  booktitle = 	 {EuroPython Conference},
    1.11 +  year = 	 {2006},
    1.12 +  month = 	 {July},
    1.13 +  note = 	 {\url{XXX}},
    1.14 +}
    1.15 +
    1.16  @Misc{web:diffstat,
    1.17    author = 	 {Thomas Dickey},
    1.18    title = 	 {\texttt{diffstat}--make a histogram of \texttt{diff} output},
     2.1 --- a/en/99defs.tex	Mon Jul 03 22:43:52 2006 -0700
     2.2 +++ b/en/99defs.tex	Tue Jul 04 15:00:18 2006 -0700
     2.3 @@ -7,7 +7,7 @@
     2.4  \newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''}
     2.5  \newcommand{\command}[1]{\index{\texttt{#1} command}\texttt{#1}}
     2.6  \newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''}
     2.7 -\newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}``\texttt{#2}''}
     2.8 +\newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
     2.9  \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}}
    2.10  
    2.11  \newsavebox{\notebox}
     3.1 --- a/en/mq.tex	Mon Jul 03 22:43:52 2006 -0700
     3.2 +++ b/en/mq.tex	Tue Jul 04 15:00:18 2006 -0700
     3.3 @@ -381,15 +381,15 @@
     3.4  
     3.5  When neither of these techniques works, \command{patch} prints a
     3.6  message saying that the hunk in question was rejected.  It saves
     3.7 -rejected hunks to a file with the same name, and an added
     3.8 -\sfilename{.rej} extension.  It also saves an unmodified copy of the
     3.9 -file with a \sfilename{.orig} extension; the copy of the file without
    3.10 -any extensions will contain any changes made by hunks that \emph{did}
    3.11 -apply cleanly.  If you have a patch that modifies \filename{foo} with
    3.12 -six hunks, and one of them fails to apply, you will have: an
    3.13 -unmodified \filename{foo.orig}, a \filename{foo.rej} containing one
    3.14 -hunk, and \filename{foo}, containing the changes made by the five
    3.15 -successful five hunks.
    3.16 +rejected hunks (also simply called ``rejects'') to a file with the
    3.17 +same name, and an added \sfilename{.rej} extension.  It also saves an
    3.18 +unmodified copy of the file with a \sfilename{.orig} extension; the
    3.19 +copy of the file without any extensions will contain any changes made
    3.20 +by hunks that \emph{did} apply cleanly.  If you have a patch that
    3.21 +modifies \filename{foo} with six hunks, and one of them fails to
    3.22 +apply, you will have: an unmodified \filename{foo.orig}, a
    3.23 +\filename{foo.rej} containing one hunk, and \filename{foo}, containing
    3.24 +the changes made by the five successful five hunks.
    3.25  
    3.26  \subsection{Beware the fuzz}
    3.27  
    3.28 @@ -420,7 +420,7 @@
    3.29  
    3.30  If your patch \emph{used to} apply cleanly, and no longer does because
    3.31  you've changed the underlying code that your patches are based on,
    3.32 -Mercurial Queues can help; see section~\ref{seq:mq:merge} for details.
    3.33 +Mercurial Queues can help; see section~\ref{sec:mq:merge} for details.
    3.34  
    3.35  Unfortunately, there aren't any great techniques for dealing with
    3.36  rejected hunks.  Most often, you'll need to view the \sfilename{.rej}
    3.37 @@ -448,10 +448,113 @@
    3.38  If you use \command{wiggle} or \command{rej}, you should be doubly
    3.39  careful to check your results when you're done.
    3.40  
    3.41 +\section{Getting the best performance out of MQ}
    3.42 +
    3.43 +MQ is very efficient at handling a large number of patches.  I ran
    3.44 +some performance experiments in mid-2006 for a talk that I gave at the
    3.45 +2006 EuroPython conference~\cite{web:europython}.  I used as my data
    3.46 +set the Linux 2.6.17-mm1 patch series, which consists of 1,738
    3.47 +patches.  I applied thes on top of a Linux kernel repository
    3.48 +containing all 27,472 revisions between Linux 2.6.12-rc2 and Linux
    3.49 +2.6.17.
    3.50 +
    3.51 +On my old, slow laptop, I was able to
    3.52 +\hgcmdargs{qpush}{\hgopt{qpush}{-a}} all 1,738 patches in 3.5 minutes,
    3.53 +and \hgcmdargs{qpop}{\hgopt{qpop}{-a}} them all in 30 seconds.  I
    3.54 +could \hgcmd{qrefresh} one of the biggest patches (which made 22,779
    3.55 +lines of changes to 287 files) in 6.6 seconds.
    3.56 +
    3.57 +Clearly, MQ is well suited to working in large trees, but there are a
    3.58 +few tricks you can use to get the best performance of it.
    3.59 +
    3.60 +First of all, try to ``batch'' operations together.  Every time you
    3.61 +run \hgcmd{qpush} or \hgcmd{qpop}, these commands scan the working
    3.62 +directory once to make sure you haven't made some changes and then
    3.63 +forgotten to run \hgcmd{qrefresh}.  On a small tree, the time that
    3.64 +this scan takes is unnoticeable.  However, on a medium-sized tree
    3.65 +(containing tens of thousands of files), it can take a second or more.
    3.66 +
    3.67 +The \hgcmd{qpush} and \hgcmd{qpop} commands allow you to push and pop
    3.68 +multiple patches at a time.  You can identify the ``destination
    3.69 +patch'' that you want to end up at.  When you \hgcmd{qpush} with a
    3.70 +destination specified, it will push patches until that patch is at the
    3.71 +top of the applied stack.  When you \hgcmd{qpop} to a destination, MQ
    3.72 +will pop patches until the destination patch \emph{is no longer}
    3.73 +applied.
    3.74 +
    3.75 +You can identify a destination patch using either the name of the
    3.76 +patch, or by number.  If you use numeric addressing, patches are
    3.77 +counted from zero; this means that the first patch is zero, the second
    3.78 +is one, and so on.
    3.79 +
    3.80  \section{Updating your patches when the underlying code changes}
    3.81  \label{sec:mq:merge}
    3.82  
    3.83 -XXX.
    3.84 +It's common to have a stack of patches on top of an underlying
    3.85 +repository that you don't modify directly.  If you're working on
    3.86 +changes to third-party code, or on a feature that is taking longer to
    3.87 +develop than the rate of change of the code beneath, you will often
    3.88 +need to sync up with the underlying code, and fix up any hunks in your
    3.89 +patches that no longer apply.  This is called \emph{rebasing} your
    3.90 +patch series.
    3.91 +
    3.92 +The simplest way to do this is to \hgcmdargs{qpop}{\hgopt{qpop}{-a}}
    3.93 +your patches, then \hgcmd{pull} changes into the underlying
    3.94 +repository, and finally \hgcmdargs{qpush}{\hgopt{qpop}{-a}} your
    3.95 +patches again.  MQ will stop pushing any time it runs across a patch
    3.96 +that fails to apply during conflicts, allowing you to fix your
    3.97 +conflicts, \hgcmd{qrefresh} the affected patch, and continue pushing
    3.98 +until you have fixed your entire stack.
    3.99 +
   3.100 +This approach is easy to use and works well if you don't expect
   3.101 +changes to the underlying code to affect how well your patches apply.
   3.102 +If your patch stack touches code that is modified frequently or
   3.103 +invasively in the underlying repository, however, fixing up rejected
   3.104 +hunks by hand quickly becomes tiresome.
   3.105 +
   3.106 +It's possible to partially automate the rebasing process.  If your
   3.107 +patches apply cleanly against some revision of the underlying repo, MQ
   3.108 +can use this information to help you to resolve conflicts between your
   3.109 +patches and a different revision.
   3.110 +
   3.111 +The process is a little involved.
   3.112 +\begin{enumerate}
   3.113 +\item To begin, \hgcmdargs{qpush}{-a} all of your patches on top of
   3.114 +  the revision where you know that they apply cleanly.
   3.115 +\item Save a backup copy of your patch directory using
   3.116 +  \hgcmdargs{qsave}{\hgopt{qsave}{-e} \hgopt{qsave}{-c}}.  This prints
   3.117 +  the name of the directory that it has saved the patches in.  It will
   3.118 +  save the patches to a directory called
   3.119 +  \sdirname{.hg/patches.\emph{N}}, where \texttt{\emph{N}} is a small
   3.120 +  integer.  It also commits a ``save changeset'' on top of your
   3.121 +  applied patches; this is for internal book-keeping, and records the
   3.122 +  states of the \sfilename{series} and \sfilename{status} files.
   3.123 +\item Use \hgcmd{pull} to bring new changes into the underlying
   3.124 +  repository.  (Don't run \hgcmdargs{pull}{-u}; see below for why.)
   3.125 +\item Update to the new tip revision, using
   3.126 +  \hgcmdargs{update}{\hgopt{update}{-C}} to override the patches you
   3.127 +  have pushed.
   3.128 +\item Merge all patches using \hgcmdargs{qpush}{\hgopt{qpush}{-m}
   3.129 +    \hgopt{qpush}{-a}}.  The \hgopt{qpush}{-m} option to \hgcmd{qpush}
   3.130 +  tells MQ to perform a three-way merge if the patch fails to apply.
   3.131 +\end{enumerate}
   3.132 +
   3.133 +During the \hgcmdargs{qpush}{\hgopt{qpush}{-m}}, each patch in the
   3.134 +\sfilename{series} file is applied normally.  If a patch applies with
   3.135 +fuzz or rejects, MQ looks at the queue you \hgcmd{qsave}d, and
   3.136 +performs a three-way merge with the corresponding changeset.  This
   3.137 +merge uses Mercurial's normal merge machinery, so it may pop up a GUI
   3.138 +merge tool to help you to resolve problems.
   3.139 +
   3.140 +When you finish resolving the effects of a patch, MQ refreshes your
   3.141 +patch based on the result of the merge.
   3.142 +
   3.143 +At the end of this process, your repository will have one extra head
   3.144 +from the old patch queue, and a copy of the old patch queue will be in
   3.145 +\sdirname{.hg/patches.\emph{N}}. You can remove the extra head using
   3.146 +\hgcmdargs{qpop}{\hgopt{qpop}{-a} \hgopt{qpop}{-n} patches.\emph{N}}
   3.147 +or \hgcmd{strip}.  You can delete \sdirname{.hg/patches.\emph{N}} once
   3.148 +you are sure that you no longer need it as a backup.
   3.149  
   3.150  \section{Managing patches in a repository}
   3.151  
   3.152 @@ -480,20 +583,21 @@
   3.153  each other, all on top of an underlying source base that they may or
   3.154  may not control.
   3.155  
   3.156 -\subsection{MQ support for managing a patch repository}
   3.157 +\subsection{MQ support for patch repositories}
   3.158  
   3.159  MQ helps you to work with the \sdirname{.hg/patches} directory as a
   3.160  repository; when you prepare a repository for working with patches
   3.161 -using \hgcmdargs{qinit}, you can pass the \hgopt{qinit}{-c} option to
   3.162 +using \hgcmd{qinit}, you can pass the \hgopt{qinit}{-c} option to
   3.163  create the \sdirname{.hg/patches} directory as a Mercurial repository.
   3.164  
   3.165  \begin{note}
   3.166    If you forget to use the \hgopt{qinit}{-c} option, you can simply go
   3.167    into the \sdirname{.hg/patches} directory at any time and run
   3.168    \hgcmd{init}.  Don't forget to add an entry for the
   3.169 -  \filename{status} file to the \filename{.hgignore} file, though
   3.170 -  (\hgopt{qinit}{-c} does this for you automatically); you
   3.171 -  \emph{really} don't want to manage the \filename{status} file.
   3.172 +  \sfilename{status} file to the \sfilename{.hgignore} file, though
   3.173 +  (\hgcmdargs{qinit}{\hgopt{qinit}{-c}} does this for you
   3.174 +  automatically); you \emph{really} don't want to manage the
   3.175 +  \sfilename{status} file.
   3.176  \end{note}
   3.177  
   3.178  As a convenience, if MQ notices that the \dirname{.hg/patches}
   3.179 @@ -512,9 +616,10 @@
   3.180  MQ cannot automatically detect changes that you make to the patch
   3.181  directory.  If you \hgcmd{pull}, manually edit, or \hgcmd{update}
   3.182  changes to patches or the \sfilename{series} file, you will have to
   3.183 -\hgcmdargs{qpop}{-a} and then \hgcmdargs{qpush}{-a} in the underlying
   3.184 -repository to see those changes show up there.  If you forget to do
   3.185 -this, you can confuse MQ's idea of which patches are applied.
   3.186 +\hgcmdargs{qpop}{\hgopt{qpop}{-a}} and then
   3.187 +\hgcmdargs{qpush}{\hgopt{qpush}{-a}} in the underlying repository to
   3.188 +see those changes show up there.  If you forget to do this, you can
   3.189 +confuse MQ's idea of which patches are applied.
   3.190  
   3.191  \section{Commands for working with patches}
   3.192