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