hgbook
changeset 106:9cbc5d0db542
Finish off advanced MQ chapter (maybe).
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Mon Oct 23 15:43:04 2006 -0700 (2006-10-23) |
parents | ecacb6b4c9fd |
children | a0d7e11db169 |
files | en/99defs.tex en/mq-collab.tex en/mq.tex examples/hg-interdiff |
line diff
1.1 --- a/en/99defs.tex Sat Oct 21 11:05:51 2006 -0700 1.2 +++ b/en/99defs.tex Mon Oct 23 15:43:04 2006 -0700 1.3 @@ -106,6 +106,9 @@ 1.4 % Interaction from the examples directory. 1.5 \newcommand{\interaction}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{examples/#1.out}} 1.6 1.7 +% Example code from the examples directory. 1.8 +\newcommand{\excode}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{../examples/#1}} 1.9 + 1.10 % Graphics inclusion. 1.11 \ifpdf 1.12 \newcommand{\grafix}[1]{\includegraphics{#1}}
2.1 --- a/en/mq-collab.tex Sat Oct 21 11:05:51 2006 -0700 2.2 +++ b/en/mq-collab.tex Mon Oct 23 15:43:04 2006 -0700 2.3 @@ -154,15 +154,12 @@ 2.4 \interaction{mq.guards.qselect.qpush} 2.5 2.6 A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}'' 2.7 -character. The name of a guard must start with an alphabetic 2.8 -character (upper or lower case) or an underscore. The rest of the 2.9 -guard's name can contain any of these characters, or a digit. These 2.10 -rules are similar to those used for variable naming in most popular 2.11 -programming languages. If you try to use a guard with an invalid 2.12 -name, MQ will complain: 2.13 -\interaction{mq.guards.qselect.error} 2.14 +character. The name of a guard must not contain white space, but most 2.15 +othter characters are acceptable. If you try to use a guard with an 2.16 +invalid name, MQ will complain: 2.17 +\interaction{mq.guards.qselect.error} 2.18 Changing the selected guards changes the patches that are applied. 2.19 -\interaction{mq.guards.qselect.quux} 2.20 +\interaction{mq.guards.qselect.quux} 2.21 You can see in the example below that negative guards take precedence 2.22 over positive guards. 2.23 \interaction{mq.guards.qselect.foobar} 2.24 @@ -250,9 +247,132 @@ 2.25 a while. 2.26 2.27 The ``backport'' and ``do not ship'' patches float at the end of the 2.28 -\sfilename{series} file in part because they'll never be shipped 2.29 -upstream. Additionally, the backport patches must be applied on top 2.30 -of all other patches. 2.31 +\sfilename{series} file. The backport patches must be applied on top 2.32 +of all other patches, and the ``do not ship'' patches might as well 2.33 +stay out of harm's way. 2.34 + 2.35 +\section{Maintaining the patch series} 2.36 + 2.37 +In my work, I use a number of guards to control which patches are to 2.38 +be applied. 2.39 + 2.40 +\begin{itemize} 2.41 +\item ``Accepted'' patches are guarded with \texttt{accepted}. I 2.42 + enable this guard most of the time. When I'm applying the patches 2.43 + on top of a tree where the patches are already present, I can turn 2.44 + this patch off, and the paptches that follow it will apply cleanly. 2.45 +\item Patches that are ``finished'', but not yet submitted, have no 2.46 + guards. If I'm applying the patch stack to a copy of the upstream 2.47 + tree, I don't need to enable any guards in order to get a reasonably 2.48 + safe source tree. 2.49 +\item Those patches that need reworking before being resubmitted are 2.50 + guarded with \texttt{rework}. 2.51 +\item For those patches that are still under development, I use 2.52 + \texttt{devel}. 2.53 +\item A backport patch may have several guards, one for each version 2.54 + of the kernel to which it applies. For example, a patch that 2.55 + backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard. 2.56 +\end{itemize} 2.57 +This variety of guards gives me considerable flexibility in 2.58 +qdetermining what kind of source tree I want to end up with. For most 2.59 +situations, the selection of appropriate guards is automated during 2.60 +the build process, but I can manually tune the guards to use for less 2.61 +common circumstances. 2.62 + 2.63 +\subsection{The art of writing backport patches} 2.64 + 2.65 +Using MQ, writing a backport patch is a simple process. All such a 2.66 +patch has to do is modify a piece of code that uses a kernel feature 2.67 +not present in the older version of the kernel, so that the driver 2.68 +continues to work correctly under that older version. 2.69 + 2.70 +A useful goal when writing a good backport patch is to make your code 2.71 +look as if it was written for the older version of the kernel you're 2.72 +targeting. The less obtrusive the patch, the easier it will be to 2.73 +understand and maintain. If you're writing a collection of backport 2.74 +patches to avoid the ``rat's nest'' effect of lots of 2.75 +\texttt{\#ifdef}s (hunks of source code that are only used 2.76 +conditionally) in your code, don't introduce version-dependent 2.77 +\texttt{\#ifdef}s into the patches. Instead, write several patches, 2.78 +each of which makes unconditional changes, and control their 2.79 +application using guards. 2.80 + 2.81 +There are two reasons to divide backport patches into a distinct 2.82 +group, away from the ``regular'' patches whose effects they modify. 2.83 +The first is that intermingling the two makes it more difficult to use 2.84 +a tool like the \hgext{patchbomb} extension to automate the process of 2.85 +submitting the patches to an upstream maintainer. The second is that 2.86 +a backport patch could perturb the context in which a subsequent 2.87 +regular patch is applied, making it impossible to apply the regular 2.88 +patch cleanly \emph{without} the earlier backport patch already being 2.89 +applied. 2.90 + 2.91 +\section{Useful tips for developing with MQ} 2.92 + 2.93 +\subsection{Organising patches in directories} 2.94 + 2.95 +If you're working on a substantial project with MQ, it's not difficult 2.96 +to accumulate a large number of patches. For example, I have one 2.97 +patch repository that contains over 250 patches. 2.98 + 2.99 +If you can group these patches into separate logical categories, you 2.100 +can if you like store them in different directories; MQ has no 2.101 +problems with patch names that contain path separators. 2.102 + 2.103 +\subsection{Viewing the history of a patch} 2.104 +\label{mq-collab:tips:interdiff} 2.105 + 2.106 +If you're developing a set of patches over a long time, it's a good 2.107 +idea to maintain them in a repository, as discussed in 2.108 +section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that 2.109 +using the \hgcmd{diff} command to look at the history of changes to a 2.110 +patch is unworkable. This is in part because you're looking at the 2.111 +second derivative of the real code (a diff of a diff), but also 2.112 +because MQ adds noise to the process by modifying time stamps and 2.113 +directory names when it updates a patch. 2.114 + 2.115 +However, you can use the \hgext{extdiff} extension, which is bundled 2.116 +with Mercurial, to turn a diff of two versions of a patch into 2.117 +something readable. To do this, you will need a third-party package 2.118 +called \package{patchutils}~\cite{web:patchutils}. This provides a 2.119 +command named \command{interdiff}, which shows the differences between 2.120 +two diffs as a diff. Used on two versions of the same diff, it 2.121 +generates a diff that represents the diff from the first to the second 2.122 +version. 2.123 + 2.124 +You can enable the \hgext{extdiff} extension in the usual way, by 2.125 +adding a line to the \rcsection{extensions} section of your \hgrc. 2.126 +\begin{codesample2} 2.127 + [extensions] 2.128 + extdiff = 2.129 +\end{codesample2} 2.130 +The \command{interdiff} command expects to be passed the names of two 2.131 +files, but the \hgext{extdiff} extension passes the program it runs a 2.132 +pair of directories, each of which can contain an arbitrary number of 2.133 +files. We thus need a small program that will run \command{interdiff} 2.134 +on each pair of files in these two directories. This program is 2.135 +available as \sfilename{hg-interdiff} in the \dirname{examples} 2.136 +directory of the source code repository that accompanies this book. 2.137 +\excode{hg-interdiff} 2.138 + 2.139 +With the \sfilename{hg-interdiff} program in your shell's search path, 2.140 +you can run it as follows, from inside an MQ patch directory: 2.141 +\begin{codesample2} 2.142 + hg extdiff -p hg-interdiff -r A:B my-change.patch 2.143 +\end{codesample2} 2.144 +Since you'll probably want to use this long-winded command a lot, you 2.145 +can get \hgext{hgext} to make it available as a normal Mercurial 2.146 +command, again by editing your \hgrc. 2.147 +\begin{codesample2} 2.148 + [extdiff] 2.149 + cmd.interdiff = hg-interdiff 2.150 +\end{codesample2} 2.151 +This directs \hgext{hgext} to make an \texttt{interdiff} command 2.152 +available, so you can now shorten the previous invocation of 2.153 +\hgcmd{extdiff} to something a little more wieldy. 2.154 +\begin{codesample2} 2.155 + hg interdiff -r A:B my-change.patch 2.156 +\end{codesample2} 2.157 2.158 %%% Local Variables: 2.159 %%% mode: latex
3.1 --- a/en/mq.tex Sat Oct 21 11:05:51 2006 -0700 3.2 +++ b/en/mq.tex Mon Oct 23 15:43:04 2006 -0700 3.3 @@ -800,6 +800,7 @@ 3.4 \end{itemize} 3.5 3.6 \section{Managing patches in a repository} 3.7 +\label{sec:mq:repo} 3.8 3.9 Because MQ's \sdirname{.hg/patches} directory resides outside a 3.10 Mercurial repository's working directory, the ``underlying'' Mercurial 3.11 @@ -894,7 +895,8 @@ 3.12 extracts subsets from a patch file. For example, given a patch that 3.13 modifies hundreds of files across dozens of directories, a single 3.14 invocation of \command{filterdiff} can generate a smaller patch that 3.15 -only touches files whose names match a particular glob pattern. 3.16 +only touches files whose names match a particular glob pattern. See 3.17 +section~\ref{mq-collab:tips:interdiff} for another example. 3.18 3.19 \section{Good ways to work with patches} 3.20
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/examples/hg-interdiff Mon Oct 23 15:43:04 2006 -0700 4.3 @@ -0,0 +1,35 @@ 4.4 +#!/usr/bin/env python 4.5 +# 4.6 +# Adapter for using interdiff with mercurial's extdiff extension. 4.7 +# Copyright 2006 Bryan O'Sullivan <bos@serpentine.com> 4.8 + 4.9 +import os, sys 4.10 + 4.11 +def walk(base): 4.12 + # yield all non-directories below the base path. 4.13 + for root, dirs, files in os.walk(base): 4.14 + for f in files: 4.15 + path = os.path.join(root, f) 4.16 + yield path[len(base)+1:], path 4.17 + 4.18 +# create list of unique file names under both directories. 4.19 +files = dict(walk(sys.argv[1])) 4.20 +files.update(walk(sys.argv[2])) 4.21 +files = files.keys() 4.22 +files.sort() 4.23 + 4.24 +def name(base, f): 4.25 + # interdiff requires two files; use /dev/null if one is missing. 4.26 + path = os.path.join(base, f) 4.27 + if os.path.exists(path): 4.28 + return path 4.29 + return '/dev/null' 4.30 + 4.31 +ret = 0 4.32 + 4.33 +for f in files: 4.34 + if os.system('interdiff "%s" "%s"' % (name(sys.argv[1], f), 4.35 + name(sys.argv[2], f))): 4.36 + ret = 1 4.37 + 4.38 +sys.exit(ret)