hgbook
diff en/mq.tex @ 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 |
line diff
1.1 --- a/en/mq.tex Mon Jul 03 22:43:52 2006 -0700 1.2 +++ b/en/mq.tex Tue Jul 04 15:00:18 2006 -0700 1.3 @@ -381,15 +381,15 @@ 1.4 1.5 When neither of these techniques works, \command{patch} prints a 1.6 message saying that the hunk in question was rejected. It saves 1.7 -rejected hunks to a file with the same name, and an added 1.8 -\sfilename{.rej} extension. It also saves an unmodified copy of the 1.9 -file with a \sfilename{.orig} extension; the copy of the file without 1.10 -any extensions will contain any changes made by hunks that \emph{did} 1.11 -apply cleanly. If you have a patch that modifies \filename{foo} with 1.12 -six hunks, and one of them fails to apply, you will have: an 1.13 -unmodified \filename{foo.orig}, a \filename{foo.rej} containing one 1.14 -hunk, and \filename{foo}, containing the changes made by the five 1.15 -successful five hunks. 1.16 +rejected hunks (also simply called ``rejects'') to a file with the 1.17 +same name, and an added \sfilename{.rej} extension. It also saves an 1.18 +unmodified copy of the file with a \sfilename{.orig} extension; the 1.19 +copy of the file without any extensions will contain any changes made 1.20 +by hunks that \emph{did} apply cleanly. If you have a patch that 1.21 +modifies \filename{foo} with six hunks, and one of them fails to 1.22 +apply, you will have: an unmodified \filename{foo.orig}, a 1.23 +\filename{foo.rej} containing one hunk, and \filename{foo}, containing 1.24 +the changes made by the five successful five hunks. 1.25 1.26 \subsection{Beware the fuzz} 1.27 1.28 @@ -420,7 +420,7 @@ 1.29 1.30 If your patch \emph{used to} apply cleanly, and no longer does because 1.31 you've changed the underlying code that your patches are based on, 1.32 -Mercurial Queues can help; see section~\ref{seq:mq:merge} for details. 1.33 +Mercurial Queues can help; see section~\ref{sec:mq:merge} for details. 1.34 1.35 Unfortunately, there aren't any great techniques for dealing with 1.36 rejected hunks. Most often, you'll need to view the \sfilename{.rej} 1.37 @@ -448,10 +448,113 @@ 1.38 If you use \command{wiggle} or \command{rej}, you should be doubly 1.39 careful to check your results when you're done. 1.40 1.41 +\section{Getting the best performance out of MQ} 1.42 + 1.43 +MQ is very efficient at handling a large number of patches. I ran 1.44 +some performance experiments in mid-2006 for a talk that I gave at the 1.45 +2006 EuroPython conference~\cite{web:europython}. I used as my data 1.46 +set the Linux 2.6.17-mm1 patch series, which consists of 1,738 1.47 +patches. I applied thes on top of a Linux kernel repository 1.48 +containing all 27,472 revisions between Linux 2.6.12-rc2 and Linux 1.49 +2.6.17. 1.50 + 1.51 +On my old, slow laptop, I was able to 1.52 +\hgcmdargs{qpush}{\hgopt{qpush}{-a}} all 1,738 patches in 3.5 minutes, 1.53 +and \hgcmdargs{qpop}{\hgopt{qpop}{-a}} them all in 30 seconds. I 1.54 +could \hgcmd{qrefresh} one of the biggest patches (which made 22,779 1.55 +lines of changes to 287 files) in 6.6 seconds. 1.56 + 1.57 +Clearly, MQ is well suited to working in large trees, but there are a 1.58 +few tricks you can use to get the best performance of it. 1.59 + 1.60 +First of all, try to ``batch'' operations together. Every time you 1.61 +run \hgcmd{qpush} or \hgcmd{qpop}, these commands scan the working 1.62 +directory once to make sure you haven't made some changes and then 1.63 +forgotten to run \hgcmd{qrefresh}. On a small tree, the time that 1.64 +this scan takes is unnoticeable. However, on a medium-sized tree 1.65 +(containing tens of thousands of files), it can take a second or more. 1.66 + 1.67 +The \hgcmd{qpush} and \hgcmd{qpop} commands allow you to push and pop 1.68 +multiple patches at a time. You can identify the ``destination 1.69 +patch'' that you want to end up at. When you \hgcmd{qpush} with a 1.70 +destination specified, it will push patches until that patch is at the 1.71 +top of the applied stack. When you \hgcmd{qpop} to a destination, MQ 1.72 +will pop patches until the destination patch \emph{is no longer} 1.73 +applied. 1.74 + 1.75 +You can identify a destination patch using either the name of the 1.76 +patch, or by number. If you use numeric addressing, patches are 1.77 +counted from zero; this means that the first patch is zero, the second 1.78 +is one, and so on. 1.79 + 1.80 \section{Updating your patches when the underlying code changes} 1.81 \label{sec:mq:merge} 1.82 1.83 -XXX. 1.84 +It's common to have a stack of patches on top of an underlying 1.85 +repository that you don't modify directly. If you're working on 1.86 +changes to third-party code, or on a feature that is taking longer to 1.87 +develop than the rate of change of the code beneath, you will often 1.88 +need to sync up with the underlying code, and fix up any hunks in your 1.89 +patches that no longer apply. This is called \emph{rebasing} your 1.90 +patch series. 1.91 + 1.92 +The simplest way to do this is to \hgcmdargs{qpop}{\hgopt{qpop}{-a}} 1.93 +your patches, then \hgcmd{pull} changes into the underlying 1.94 +repository, and finally \hgcmdargs{qpush}{\hgopt{qpop}{-a}} your 1.95 +patches again. MQ will stop pushing any time it runs across a patch 1.96 +that fails to apply during conflicts, allowing you to fix your 1.97 +conflicts, \hgcmd{qrefresh} the affected patch, and continue pushing 1.98 +until you have fixed your entire stack. 1.99 + 1.100 +This approach is easy to use and works well if you don't expect 1.101 +changes to the underlying code to affect how well your patches apply. 1.102 +If your patch stack touches code that is modified frequently or 1.103 +invasively in the underlying repository, however, fixing up rejected 1.104 +hunks by hand quickly becomes tiresome. 1.105 + 1.106 +It's possible to partially automate the rebasing process. If your 1.107 +patches apply cleanly against some revision of the underlying repo, MQ 1.108 +can use this information to help you to resolve conflicts between your 1.109 +patches and a different revision. 1.110 + 1.111 +The process is a little involved. 1.112 +\begin{enumerate} 1.113 +\item To begin, \hgcmdargs{qpush}{-a} all of your patches on top of 1.114 + the revision where you know that they apply cleanly. 1.115 +\item Save a backup copy of your patch directory using 1.116 + \hgcmdargs{qsave}{\hgopt{qsave}{-e} \hgopt{qsave}{-c}}. This prints 1.117 + the name of the directory that it has saved the patches in. It will 1.118 + save the patches to a directory called 1.119 + \sdirname{.hg/patches.\emph{N}}, where \texttt{\emph{N}} is a small 1.120 + integer. It also commits a ``save changeset'' on top of your 1.121 + applied patches; this is for internal book-keeping, and records the 1.122 + states of the \sfilename{series} and \sfilename{status} files. 1.123 +\item Use \hgcmd{pull} to bring new changes into the underlying 1.124 + repository. (Don't run \hgcmdargs{pull}{-u}; see below for why.) 1.125 +\item Update to the new tip revision, using 1.126 + \hgcmdargs{update}{\hgopt{update}{-C}} to override the patches you 1.127 + have pushed. 1.128 +\item Merge all patches using \hgcmdargs{qpush}{\hgopt{qpush}{-m} 1.129 + \hgopt{qpush}{-a}}. The \hgopt{qpush}{-m} option to \hgcmd{qpush} 1.130 + tells MQ to perform a three-way merge if the patch fails to apply. 1.131 +\end{enumerate} 1.132 + 1.133 +During the \hgcmdargs{qpush}{\hgopt{qpush}{-m}}, each patch in the 1.134 +\sfilename{series} file is applied normally. If a patch applies with 1.135 +fuzz or rejects, MQ looks at the queue you \hgcmd{qsave}d, and 1.136 +performs a three-way merge with the corresponding changeset. This 1.137 +merge uses Mercurial's normal merge machinery, so it may pop up a GUI 1.138 +merge tool to help you to resolve problems. 1.139 + 1.140 +When you finish resolving the effects of a patch, MQ refreshes your 1.141 +patch based on the result of the merge. 1.142 + 1.143 +At the end of this process, your repository will have one extra head 1.144 +from the old patch queue, and a copy of the old patch queue will be in 1.145 +\sdirname{.hg/patches.\emph{N}}. You can remove the extra head using 1.146 +\hgcmdargs{qpop}{\hgopt{qpop}{-a} \hgopt{qpop}{-n} patches.\emph{N}} 1.147 +or \hgcmd{strip}. You can delete \sdirname{.hg/patches.\emph{N}} once 1.148 +you are sure that you no longer need it as a backup. 1.149 1.150 \section{Managing patches in a repository} 1.151 1.152 @@ -480,20 +583,21 @@ 1.153 each other, all on top of an underlying source base that they may or 1.154 may not control. 1.155 1.156 -\subsection{MQ support for managing a patch repository} 1.157 +\subsection{MQ support for patch repositories} 1.158 1.159 MQ helps you to work with the \sdirname{.hg/patches} directory as a 1.160 repository; when you prepare a repository for working with patches 1.161 -using \hgcmdargs{qinit}, you can pass the \hgopt{qinit}{-c} option to 1.162 +using \hgcmd{qinit}, you can pass the \hgopt{qinit}{-c} option to 1.163 create the \sdirname{.hg/patches} directory as a Mercurial repository. 1.164 1.165 \begin{note} 1.166 If you forget to use the \hgopt{qinit}{-c} option, you can simply go 1.167 into the \sdirname{.hg/patches} directory at any time and run 1.168 \hgcmd{init}. Don't forget to add an entry for the 1.169 - \filename{status} file to the \filename{.hgignore} file, though 1.170 - (\hgopt{qinit}{-c} does this for you automatically); you 1.171 - \emph{really} don't want to manage the \filename{status} file. 1.172 + \sfilename{status} file to the \sfilename{.hgignore} file, though 1.173 + (\hgcmdargs{qinit}{\hgopt{qinit}{-c}} does this for you 1.174 + automatically); you \emph{really} don't want to manage the 1.175 + \sfilename{status} file. 1.176 \end{note} 1.177 1.178 As a convenience, if MQ notices that the \dirname{.hg/patches} 1.179 @@ -512,9 +616,10 @@ 1.180 MQ cannot automatically detect changes that you make to the patch 1.181 directory. If you \hgcmd{pull}, manually edit, or \hgcmd{update} 1.182 changes to patches or the \sfilename{series} file, you will have to 1.183 -\hgcmdargs{qpop}{-a} and then \hgcmdargs{qpush}{-a} in the underlying 1.184 -repository to see those changes show up there. If you forget to do 1.185 -this, you can confuse MQ's idea of which patches are applied. 1.186 +\hgcmdargs{qpop}{\hgopt{qpop}{-a}} and then 1.187 +\hgcmdargs{qpush}{\hgopt{qpush}{-a}} in the underlying repository to 1.188 +see those changes show up there. If you forget to do this, you can 1.189 +confuse MQ's idea of which patches are applied. 1.190 1.191 \section{Commands for working with patches} 1.192