hgbook

changeset 19:187702df428b

Piles of new content for MQ chapter - cookbook stuff.
author Bryan O'Sullivan <bos@serpentine.com>
date Fri Jul 07 19:56:53 2006 -0700 (2006-07-07)
parents e6f4088ebe52
children 2888fe6176b3
files en/99defs.tex en/Makefile en/examples/data/netplug-1.2.5.tar.bz2 en/examples/data/netplug-1.2.8.tar.bz2 en/examples/data/remove-redundant-null-checks.patch en/examples/mq.diff en/examples/mq.tarball en/examples/mq.tools en/examples/run-example en/mq.tex
line diff
     1.1 --- a/en/99defs.tex	Tue Jul 04 16:41:31 2006 -0700
     1.2 +++ b/en/99defs.tex	Fri Jul 07 19:56:53 2006 -0700
     1.3 @@ -6,8 +6,10 @@
     1.4  \newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}}
     1.5  \newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''}
     1.6  \newcommand{\command}[1]{\index{\texttt{#1} command}\texttt{#1}}
     1.7 +\newcommand{\cmdargs}[2]{\index{\texttt{#1} command}\texttt{#1 #2}}
     1.8  \newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''}
     1.9  \newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
    1.10 +\newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
    1.11  \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}}
    1.12  
    1.13  \newsavebox{\notebox}
     2.1 --- a/en/Makefile	Tue Jul 04 16:41:31 2006 -0700
     2.2 +++ b/en/Makefile	Fri Jul 07 19:56:53 2006 -0700
     2.3 @@ -16,6 +16,9 @@
     2.4  example-sources := \
     2.5  	examples/run-example \
     2.6  	examples/mq.qinit-help \
     2.7 +	examples/mq.diff \
     2.8 +	examples/mq.tarball \
     2.9 +	examples/mq.tools \
    2.10  	examples/mq.tutorial
    2.11  
    2.12  latex-options = \
     3.1 Binary file en/examples/data/netplug-1.2.5.tar.bz2 has changed
     4.1 Binary file en/examples/data/netplug-1.2.8.tar.bz2 has changed
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/en/examples/data/remove-redundant-null-checks.patch	Fri Jul 07 19:56:53 2006 -0700
     5.3 @@ -0,0 +1,190 @@
     5.4 +
     5.5 +From: Jesper Juhl <jesper.juhl@gmail.com>
     5.6 +
     5.7 +Remove redundant NULL chck before kfree + tiny CodingStyle cleanup for
     5.8 +drivers/
     5.9 +
    5.10 +Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com>
    5.11 +Signed-off-by: Andrew Morton <akpm@osdl.org>
    5.12 +---
    5.13 +
    5.14 + drivers/char/agp/sgi-agp.c        |    5 ++---
    5.15 + drivers/char/hvcs.c               |   11 +++++------
    5.16 + drivers/message/fusion/mptfc.c    |    6 ++----
    5.17 + drivers/message/fusion/mptsas.c   |    3 +--
    5.18 + drivers/net/fs_enet/fs_enet-mii.c |    3 +--
    5.19 + drivers/net/wireless/ipw2200.c    |   22 ++++++----------------
    5.20 + drivers/scsi/libata-scsi.c        |    4 +---
    5.21 + drivers/video/au1100fb.c          |    3 +--
    5.22 + 8 files changed, 19 insertions(+), 38 deletions(-)
    5.23 +
    5.24 +diff -puN drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/agp/sgi-agp.c
    5.25 +--- a/drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers
    5.26 ++++ a/drivers/char/agp/sgi-agp.c
    5.27 +@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void)
    5.28 + 
    5.29 + static void __devexit agp_sgi_cleanup(void)
    5.30 + {
    5.31 +-	if (sgi_tioca_agp_bridges)
    5.32 +-		kfree(sgi_tioca_agp_bridges);
    5.33 +-	sgi_tioca_agp_bridges=NULL;
    5.34 ++	kfree(sgi_tioca_agp_bridges);
    5.35 ++	sgi_tioca_agp_bridges = NULL;
    5.36 + }
    5.37 + 
    5.38 + module_init(agp_sgi_init);
    5.39 +diff -puN drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/hvcs.c
    5.40 +--- a/drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers
    5.41 ++++ a/drivers/char/hvcs.c
    5.42 +@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = 
    5.43 + static int hvcs_alloc_index_list(int n)
    5.44 + {
    5.45 + 	int i;
    5.46 ++
    5.47 + 	hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
    5.48 + 	if (!hvcs_index_list)
    5.49 + 		return -ENOMEM;
    5.50 + 	hvcs_index_count = n;
    5.51 +-	for(i = 0; i < hvcs_index_count; i++)
    5.52 ++	for (i = 0; i < hvcs_index_count; i++)
    5.53 + 		hvcs_index_list[i] = -1;
    5.54 + 	return 0;
    5.55 + }
    5.56 +@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n)
    5.57 + static void hvcs_free_index_list(void)
    5.58 + {
    5.59 + 	/* Paranoia check to be thorough. */
    5.60 +-	if (hvcs_index_list) {
    5.61 +-		kfree(hvcs_index_list);
    5.62 +-		hvcs_index_list = NULL;
    5.63 +-		hvcs_index_count = 0;
    5.64 +-	}
    5.65 ++	kfree(hvcs_index_list);
    5.66 ++	hvcs_index_list = NULL;
    5.67 ++	hvcs_index_count = 0;
    5.68 + }
    5.69 + 
    5.70 + static int __init hvcs_module_init(void)
    5.71 +diff -puN drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptfc.c
    5.72 +--- a/drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers
    5.73 ++++ a/drivers/message/fusion/mptfc.c
    5.74 +@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in
    5.75 + 	}
    5.76 + 
    5.77 +  out:
    5.78 +-	if (pp0_array)
    5.79 +-		kfree(pp0_array);
    5.80 +-	if (p0_array)
    5.81 +-		kfree(p0_array);
    5.82 ++	kfree(pp0_array);
    5.83 ++	kfree(p0_array);
    5.84 + 	return rc;
    5.85 + }
    5.86 + 
    5.87 +diff -puN drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptsas.c
    5.88 +--- a/drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers
    5.89 ++++ a/drivers/message/fusion/mptsas.c
    5.90 +@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
    5.91 + 	return 0;
    5.92 + 
    5.93 +  out_free_port_info:
    5.94 +-	if (hba)
    5.95 +-		kfree(hba);
    5.96 ++	kfree(hba);
    5.97 +  out:
    5.98 + 	return error;
    5.99 + }
   5.100 +diff -puN drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/fs_enet/fs_enet-mii.c
   5.101 +--- a/drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers
   5.102 ++++ a/drivers/net/fs_enet/fs_enet-mii.c
   5.103 +@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bu
   5.104 + 	return bus;
   5.105 + 
   5.106 + err:
   5.107 +-	if (bus)
   5.108 +-		kfree(bus);
   5.109 ++	kfree(bus);
   5.110 + 	return ERR_PTR(ret);
   5.111 + }
   5.112 + 
   5.113 +diff -puN drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/wireless/ipw2200.c
   5.114 +--- a/drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers
   5.115 ++++ a/drivers/net/wireless/ipw2200.c
   5.116 +@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_er
   5.117 + 	return error;
   5.118 + }
   5.119 + 
   5.120 +-static void ipw_free_error_log(struct ipw_fw_error *error)
   5.121 +-{
   5.122 +-	if (error)
   5.123 +-		kfree(error);
   5.124 +-}
   5.125 +-
   5.126 + static ssize_t show_event_log(struct device *d,
   5.127 + 			      struct device_attribute *attr, char *buf)
   5.128 + {
   5.129 +@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device
   5.130 + 			   const char *buf, size_t count)
   5.131 + {
   5.132 + 	struct ipw_priv *priv = dev_get_drvdata(d);
   5.133 +-	if (priv->error) {
   5.134 +-		ipw_free_error_log(priv->error);
   5.135 +-		priv->error = NULL;
   5.136 +-	}
   5.137 ++
   5.138 ++	kfree(priv->error);
   5.139 ++	priv->error = NULL;
   5.140 + 	return count;
   5.141 + }
   5.142 + 
   5.143 +@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_p
   5.144 + 				struct ipw_fw_error *error =
   5.145 + 				    ipw_alloc_error_log(priv);
   5.146 + 				ipw_dump_error_log(priv, error);
   5.147 +-				if (error)
   5.148 +-					ipw_free_error_log(error);
   5.149 ++				kfree(error);
   5.150 + 			}
   5.151 + #endif
   5.152 + 		} else {
   5.153 +@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_de
   5.154 + 		}
   5.155 + 	}
   5.156 + 
   5.157 +-	if (priv->error) {
   5.158 +-		ipw_free_error_log(priv->error);
   5.159 +-		priv->error = NULL;
   5.160 +-	}
   5.161 ++	kfree(priv->error);
   5.162 ++	priv->error = NULL;
   5.163 + 
   5.164 + #ifdef CONFIG_IPW2200_PROMISCUOUS
   5.165 + 	ipw_prom_free(priv);
   5.166 +diff -puN drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers drivers/scsi/libata-scsi.c
   5.167 +--- a/drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers
   5.168 ++++ a/drivers/scsi/libata-scsi.c
   5.169 +@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *sc
   5.170 + 	 && copy_to_user(arg + sizeof(args), argbuf, argsize))
   5.171 + 		rc = -EFAULT;
   5.172 + error:
   5.173 +-	if (argbuf)
   5.174 +-		kfree(argbuf);
   5.175 +-
   5.176 ++	kfree(argbuf);
   5.177 + 	return rc;
   5.178 + }
   5.179 + 
   5.180 +diff -puN drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers drivers/video/au1100fb.c
   5.181 +--- a/drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers
   5.182 ++++ a/drivers/video/au1100fb.c
   5.183 +@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void)
   5.184 + {
   5.185 + 	driver_unregister(&au1100fb_driver);
   5.186 + 
   5.187 +-	if (drv_info.opt_mode)
   5.188 +-		kfree(drv_info.opt_mode);
   5.189 ++	kfree(drv_info.opt_mode);
   5.190 + }
   5.191 + 
   5.192 + module_init(au1100fb_init);
   5.193 +_
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/en/examples/mq.diff	Fri Jul 07 19:56:53 2006 -0700
     6.3 @@ -0,0 +1,12 @@
     6.4 +#$ name: diff
     6.5 +
     6.6 +echo 'this is my first line' > oldfile
     6.7 +echo 'my first line is here' > newfile
     6.8 +
     6.9 +diff -u oldfile newfile > tiny.patch
    6.10 +
    6.11 +cat tiny.patch
    6.12 +
    6.13 +patch < tiny.patch
    6.14 +
    6.15 +cat newfile
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/en/examples/mq.tarball	Fri Jul 07 19:56:53 2006 -0700
     7.3 @@ -0,0 +1,48 @@
     7.4 +cp $EXAMPLE_DIR/data/netplug-*.tar.bz2 .
     7.5 +ln -s /bin/true download
     7.6 +
     7.7 +#$ name: download
     7.8 +
     7.9 +download netplug-1.2.5.tar.bz2
    7.10 +tar jxf netplug-1.2.5.tar.bz2
    7.11 +cd netplug-1.2.5
    7.12 +hg init
    7.13 +hg commit -q --addremove --message netplug-1.2.5
    7.14 +cd ..
    7.15 +hg clone netplug-1.2.5 netplug
    7.16 +
    7.17 +#$ name:
    7.18 +
    7.19 +cd netplug
    7.20 +echo '[extensions]' >> $HGRC
    7.21 +echo 'hgext.mq =' >> $HGRC
    7.22 +cd ..
    7.23 +
    7.24 +#$ name: qinit
    7.25 +
    7.26 +cd netplug
    7.27 +hg qinit
    7.28 +hg qnew -m 'fix build problem with gcc 4' build-fix.patch
    7.29 +perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c
    7.30 +hg qrefresh
    7.31 +hg tip -p
    7.32 +
    7.33 +#$ name: newsource
    7.34 +
    7.35 +hg qpop -a
    7.36 +cd ..
    7.37 +download netplug-1.2.8.tar.bz2
    7.38 +hg clone netplug-1.2.5 netplug-1.2.8
    7.39 +cd netplug-1.2.8
    7.40 +hg locate -0 | xargs -0 rm
    7.41 +cd ..
    7.42 +tar jxf netplug-1.2.8.tar.bz2
    7.43 +cd netplug-1.2.8
    7.44 +hg commit --addremove --message netplug-1.2.8
    7.45 +
    7.46 +#$ name: repush
    7.47 +
    7.48 +cd ../netplug
    7.49 +hg pull ../netplug-1.2.8
    7.50 +hg qpush -a
    7.51 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/en/examples/mq.tools	Fri Jul 07 19:56:53 2006 -0700
     8.3 @@ -0,0 +1,9 @@
     8.4 +cp $EXAMPLE_DIR/data/remove-redundant-null-checks.patch .
     8.5 +
     8.6 +#$ name: tools
     8.7 +diffstat -p1 remove-redundant-null-checks.patch
     8.8 +
     8.9 +filterdiff -i '*/video/*' remove-redundant-null-checks.patch
    8.10 +
    8.11 +#$ name: lsdiff
    8.12 +lsdiff -nvv remove-redundant-null-checks.patch
     9.1 --- a/en/examples/run-example	Tue Jul 04 16:41:31 2006 -0700
     9.2 +++ b/en/examples/run-example	Fri Jul 07 19:56:53 2006 -0700
     9.3 @@ -76,6 +76,7 @@
     9.4          rcfp = open(rcfile, 'w')
     9.5          print >> rcfp, 'PS1="%s"' % self.prompt
     9.6          print >> rcfp, 'unset HISTFILE'
     9.7 +        print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd()
     9.8          print >> rcfp, 'export LANG=C'
     9.9          print >> rcfp, 'export LC_ALL=C'
    9.10          print >> rcfp, 'export TZ=GMT'
    9.11 @@ -117,7 +118,7 @@
    9.12                          if nl: hunk += '\n'
    9.13                      ofp.write(hunk)
    9.14                      # then its output
    9.15 -                    ofp.write(output)
    9.16 +                    ofp.write(tex_escape(output))
    9.17              self.status('\n')
    9.18          finally:
    9.19              try:
    9.20 @@ -140,7 +141,9 @@
    9.21      for name in os.listdir(path):
    9.22          if name == 'run-example' or name.startswith('.'): continue
    9.23          if name.endswith('.out') or name.endswith('~'): continue
    9.24 -        example(os.path.join(path, name)).run()
    9.25 +        pathname = os.path.join(path, name)
    9.26 +        if os.path.isfile(pathname):
    9.27 +            example(pathname).run()
    9.28      print >> open(os.path.join(path, '.run'), 'w'), time.asctime()
    9.29  
    9.30  if __name__ == '__main__':
    10.1 --- a/en/mq.tex	Tue Jul 04 16:41:31 2006 -0700
    10.2 +++ b/en/mq.tex	Fri Jul 07 19:56:53 2006 -0700
    10.3 @@ -126,6 +126,62 @@
    10.4  Because quilt does not care about revision control tools, it is still
    10.5  a tremendously useful piece of software to know about for situations
    10.6  where you cannot use Mercurial and MQ.
    10.7 +
    10.8 +\section{Understanding patches}
    10.9 +
   10.10 +Because MQ doesn't hide its patch-oriented nature, it is helpful to
   10.11 +understand what patches are, and a little about the tools that work
   10.12 +with them.
   10.13 +
   10.14 +The traditional Unix \command{diff} command compares two files, and
   10.15 +prints a list of differences between them. The \command{patch} command
   10.16 +understands these differences as \emph{modifications} to make to a
   10.17 +file.  Take a look at figure~\ref{ex:mq:diff} for a simple example of
   10.18 +these commands in action.
   10.19 +
   10.20 +\begin{figure}[ht]
   10.21 +  \interaction{mq.diff.diff}
   10.22 +  \caption{Simple uses of the \command{diff} and \command{patch} commands}
   10.23 +  \label{ex:mq:diff}
   10.24 +\end{figure}
   10.25 +
   10.26 +The type of file that \command{diff} generates (and \command{patch}
   10.27 +takes as input) is called a ``patch'' or a ``diff''; there is no
   10.28 +difference between a patch and a diff.  (We'll use the term ``patch'',
   10.29 +since it's more commonly used.)
   10.30 +
   10.31 +A patch file can start with arbitrary text; the \command{patch}
   10.32 +command ignores this text, but MQ uses it as the commit message when
   10.33 +creating changesets.  To find the beginning of the patch content,
   10.34 +\command{patch} searches for the first line that starts with the
   10.35 +string ``\texttt{diff~-}''.
   10.36 +
   10.37 +MQ works with \emph{unified} diffs (\command{patch} can accept several
   10.38 +other diff formats, but MQ doesn't).  A unified diff contains two
   10.39 +kinds of header.  The \emph{file header} describes the file being
   10.40 +modified; it contains the name of the file to modify.  When
   10.41 +\command{patch} sees a new file header, it looks for a file with that
   10.42 +name to start modifying.
   10.43 +
   10.44 +After the file header comes a series of \emph{hunks}.  Each hunk
   10.45 +starts with a header; this identifies the range of line numbers within
   10.46 +the file that the hunk should modify.  Following the header, a hunk
   10.47 +starts and ends with a few (usually three) lines of text from the
   10.48 +unmodified file; these are called the \emph{context} for the hunk.  If
   10.49 +there's only a small amount of context between successive hunks,
   10.50 +\command{diff} doesn't print a new hunk header; it just runs the hunks
   10.51 +together, with a few lines of context between modifications.
   10.52 +
   10.53 +Each line of context begins with a space character.  Within the hunk,
   10.54 +a line that begins with ``\texttt{-}'' means ``remove this line,''
   10.55 +while a line that begins with ``\texttt{+}'' means ``insert this
   10.56 +line.''  For example, a line that is modified is represented by one
   10.57 +deletion and one insertion.
   10.58 +
   10.59 +We will return to ome of the more subtle aspects of patches later (in
   10.60 +section~\ref{ex:mq:adv-patch}), but you should have enough information
   10.61 +now to use MQ.
   10.62 +
   10.63  \section{Getting started with Mercurial Queues}
   10.64  \label{sec:mq:start}
   10.65  
   10.66 @@ -200,6 +256,7 @@
   10.67  working directory as you usually would.  All of the normal Mercurial
   10.68  commands, such as \hgcmd{diff} and \hgcmd{annotate}, work exactly as
   10.69  they did before.
   10.70 +
   10.71  \subsection{Refreshing a patch}
   10.72  
   10.73  When you reach a point where you want to save your work, use the
   10.74 @@ -319,45 +376,12 @@
   10.75  \hgcmd{qrefresh} the core patch, and \hgcmd{qpush} back to the UI
   10.76  patch to continue where you left off.
   10.77  
   10.78 -\section{Mercurial Queues and GNU patch}
   10.79 -\label{sec:mq:patch}
   10.80 -
   10.81 -MQ uses the GNU \command{patch} command to apply patches.  Because MQ
   10.82 -doesn't hide its patch-oriented nature, it is helpful to understand
   10.83 -the data that MQ and \command{patch} work with, and a few aspects of
   10.84 -how \command{patch} operates.
   10.85 -
   10.86 -The \command{diff} command generates a list of modifications by
   10.87 -comparing two files.  The \command{patch} command applies a list of
   10.88 -modifications to a file.  The kinds of files that \command{diff} and
   10.89 -\command{patch} work with are referred to as both ``diffs'' and
   10.90 -``patches;'' there is no difference between a diff and a patch.
   10.91 -
   10.92 -A patch file can start with arbitrary text; MQ uses this text as the
   10.93 -commit message when creating changesets.  It treats the first line
   10.94 -that starts with the string ``\texttt{diff~-}'' as the separator
   10.95 -between header and content.
   10.96 -
   10.97 -MQ works with \emph{unified} diffs (\command{patch} can accept several
   10.98 -other diff formats, but MQ doesn't).  A unified diff contains two
   10.99 -kinds of header.  The \emph{file header} describes the file being
  10.100 -modified; it contains the name of the file to modify.  When
  10.101 -\command{patch} sees a new file header, it looks for a file with that
  10.102 -name to start modifying.
  10.103 -
  10.104 -After the file header comes a series of \emph{hunks}.  Each hunk
  10.105 -starts with a header; this identifies the range of line numbers within
  10.106 -the file that the hunk should modify.  Following the header, a hunk
  10.107 -starts and ends with a few (usually three) lines of text from the
  10.108 -unmodified file; these are called the \emph{context} for the hunk.
  10.109 -Each unmodified line begins with a space characters.  Within the hunk,
  10.110 -a line that begins with ``\texttt{-}'' means ``remove this line,''
  10.111 -while a line that begins with ``\texttt{+}'' means ``insert this
  10.112 -line.''  For example, a line that is modified is represented by one
  10.113 -deletion and one insertion.
  10.114 -
  10.115 -The \command{diff} command runs hunks together when there's not enough
  10.116 -context between modifications to justify
  10.117 +\section{More about patches}
  10.118 +\label{sec:mq:adv-patch}
  10.119 +
  10.120 +MQ uses the GNU \command{patch} command to apply patches, so it's
  10.121 +helpful to know about a few more detailed aspects of how
  10.122 +\command{patch} works.
  10.123  
  10.124  When \command{patch} applies a hunk, it tries a handful of
  10.125  successively less accurate strategies to try to make the hunk apply.
  10.126 @@ -622,6 +646,7 @@
  10.127  confuse MQ's idea of which patches are applied.
  10.128  
  10.129  \section{Commands for working with patches}
  10.130 +\label{sec:mq:tools}
  10.131  
  10.132  Once you've been working with patches for a while, you'll find
  10.133  yourself hungry for tools that will help you to understand and
  10.134 @@ -636,6 +661,12 @@
  10.135  do clever things with prefixes of file names that inevitably confuse
  10.136  at least me.)
  10.137  
  10.138 +\begin{figure}[ht]
  10.139 +  \interaction{mq.tools.tools}
  10.140 +  \caption{The \command{diffstat}, \command{filterdiff}, and \command{lsdiff} commands}
  10.141 +  \label{ex:mq:tools}
  10.142 +\end{figure}
  10.143 +
  10.144  The \package{patchutils} package~\cite{web:patchutils} is invaluable.
  10.145  It provides a set of small utilities that follow the ``Unix
  10.146  philosophy;'' each does one useful thing with a patch.  The
  10.147 @@ -645,6 +676,122 @@
  10.148  invocation of \command{filterdiff} can generate a smaller patch that
  10.149  only touches files whose names match a particular glob pattern.
  10.150  
  10.151 +\section{Good ways to work with patches}
  10.152 +
  10.153 +Whether you are working on a patch series to submit to a free software
  10.154 +or open source project, or a series that you intend to treat as a
  10.155 +sequence of regular changesets when you're done, you can use some
  10.156 +simple techniques to keep your work well organised.
  10.157 +
  10.158 +Give your patches descriptive names.  A good name for a patch might be
  10.159 +\filename{rework-device-alloc.patch}, because it will immediately give
  10.160 +you a hint what the purpose of the patch is.  Long names shouldn't be
  10.161 +a problem; you won't be typing the names often, but you \emph{will} be
  10.162 +running commands like \hgcmd{qapplied} and \hgcmd{qtop} over and over.
  10.163 +Good naming becomes especially important when you have a number of
  10.164 +patches to work with, or if you are juggling a number of different
  10.165 +tasks and your patches only get a fraction of your attention.
  10.166 +
  10.167 +Be aware of what patch you're working on.  Use the \hgcmd{qtop}
  10.168 +command and skim over the text of your patches frequently---for
  10.169 +example, using \hgcmdargs{tip}{\hgopt{tip}{-p}})---to be sure of where
  10.170 +you stand.  I have several times worked on and \hgcmd{qrefresh}ed a
  10.171 +patch other than the one I intended, and it's often tricky to migrate
  10.172 +changes into the right patch after making them in the wrong one.
  10.173 +
  10.174 +For this reason, it is very much worth investing a little time to
  10.175 +learn how to use some of the third-party tools I described in
  10.176 +section~\ref{sec:mq:tools}, particularly \command{diffstat} and
  10.177 +\command{filterdiff}.  The former will give you a quick idea of what
  10.178 +changes your patch is making, while the latter makes it easy to splice
  10.179 +hunks selectively out of one patch and into another.
  10.180 +
  10.181 +\section{MQ cookbook}
  10.182 +
  10.183 +\subsection{Manage ``trivial'' patches}
  10.184 +
  10.185 +Because the overhead of dropping files into a new Mercurial repository
  10.186 +is so low, it makes a lot of sense to manage patches this way even if
  10.187 +you simply want to make a few changes to a source tarball that you
  10.188 +downloaded.
  10.189 +
  10.190 +Begin by downloading and unpacking the source tarball,
  10.191 +and turning it into a Mercurial repository.
  10.192 +\interaction{mq.tarball.download}
  10.193 +
  10.194 +Continue by creating a patch stack and making your changes.
  10.195 +\interaction{mq.tarball.qinit}
  10.196 +
  10.197 +Let's say a few weeks or months pass, and your package author releases
  10.198 +a new version.  First, bring their changes into the repository.
  10.199 +\interaction{mq.tarball.newsource}
  10.200 +The pipeline starting with \hgcmd{locate} above deletes all files in
  10.201 +the working directory, so that \hgcmd{commit}'s
  10.202 +\hgopt{commit}{--addremove} option can actually tell which files have
  10.203 +really been removed in the newer version of the source.
  10.204 +
  10.205 +Finally, you can apply your patches on top of the new tree.
  10.206 +\interaction{mq.tarball.repush}
  10.207 +
  10.208 +\subsection{Combining entire patches}
  10.209 +\label{sec:mq:combine}
  10.210 +
  10.211 +It's easy to combine entire patches.
  10.212 +
  10.213 +\begin{enumerate}
  10.214 +\item \hgcmd{qpop} your applied patches until neither patch is
  10.215 +  applied.
  10.216 +\item Concatenate the patches that you want to combine together:
  10.217 +  \begin{codesample4}
  10.218 +    cat patch-to-drop.patch >> patch-to-augment.patch
  10.219 +  \end{codesample4}
  10.220 +  The description from the first patch (if you have one) will be used
  10.221 +  as the commit comment when you \hgcmd{qpush} the combined patch.
  10.222 +  Edit the patch description if you need to.
  10.223 +\item Use the \hgcmd{qdel} command to delete the patch you're dropping
  10.224 +  from the \sfilename{series} file.
  10.225 +\item \hgcmd{qpush} the combined patch.  Fix up any rejects.
  10.226 +\item \hgcmd{qrefresh} the combined patch to tidy it up.
  10.227 +\end{enumerate}
  10.228 +
  10.229 +\subsection{Merging part of one patch into another}
  10.230 +
  10.231 +Merging \emph{part} of one patch into another is more difficult than
  10.232 +combining entire patches.
  10.233 +
  10.234 +If you want to move changes to entire files, you can use
  10.235 +\command{filterdiff}'s \cmdopt{filterdiff}{-i} and
  10.236 +\cmdopt{filterdiff}{-x} options to choose the modifications to snip
  10.237 +out of one patch, concatenating its output onto the end of the patch
  10.238 +you want to merge into.  You usually won't need to modify the patch
  10.239 +you've merged the changes from.  Instead, MQ will report some rejected
  10.240 +hunks when you \hgcmd{qpush} it (from the hunks you moved into the
  10.241 +other patch), and you can simply \hgcmd{qrefresh} the patch to drop
  10.242 +the duplicate hunks.
  10.243 +
  10.244 +If you have a patch that has multiple hunks modifying a file, and you
  10.245 +only want to move a few of those hunks, the job becomes more messy,
  10.246 +but you can still partly automate it.  Use \cmdargs{lsdiff}{-nvv} to
  10.247 +print some metadata about the patch.
  10.248 +\interaction{mq.tools.lsdiff}
  10.249 +
  10.250 +This command prints three different kinds of number:
  10.251 +\begin{itemize}
  10.252 +\item a \emph{file number} to identify each file modified in the patch;
  10.253 +\item the line number within a modified file that a hunk starts at; and
  10.254 +\item a \emph{hunk number} to identify that hunk.
  10.255 +\end{itemize}
  10.256 +
  10.257 +You'll have to use some visual inspection, and reading of the patch,
  10.258 +to identify the file and hunk numbers you'll want, but you can then
  10.259 +pass them to to \command{filterdiff}'s \cmdopt{filterdiff}{--files}
  10.260 +and \cmdopt{filterdiff}{--hunks} options, to select exactly the file
  10.261 +and hunk you want to extract.
  10.262 +
  10.263 +Once you have this hunk, you can concatenate it onto the end of your
  10.264 +destination patch and continue with the remainder of
  10.265 +section~\ref{sec:mq:combine}.
  10.266 +
  10.267  %%% Local Variables: 
  10.268  %%% mode: latex
  10.269  %%% TeX-master: "00book"