hgbook

changeset 24:a752b0fd3c10

Merge.
author Bryan O'Sullivan <bos@serpentine.com>
date Sun Jul 09 21:47:15 2006 -0700 (2006-07-09)
parents 9457add294b8 2888fe6176b3
children 9d5b6d303ef5
files en/Makefile en/examples/run-example
line diff
     1.1 --- a/.hgignore	Sun Jul 09 21:47:02 2006 -0700
     1.2 +++ b/.hgignore	Sun Jul 09 21:47:15 2006 -0700
     1.3 @@ -15,6 +15,7 @@
     1.4  *.ind
     1.5  *.lg
     1.6  *.lo[fgt]
     1.7 +*.orig
     1.8  *.out
     1.9  *.pdf
    1.10  *.png
     2.1 --- a/en/99defs.tex	Sun Jul 09 21:47:02 2006 -0700
     2.2 +++ b/en/99defs.tex	Sun Jul 09 21:47:15 2006 -0700
     2.3 @@ -6,8 +6,10 @@
     2.4  \newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}}
     2.5  \newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''}
     2.6  \newcommand{\command}[1]{\index{\texttt{#1} command}\texttt{#1}}
     2.7 +\newcommand{\cmdargs}[2]{\index{\texttt{#1} command}\texttt{#1 #2}}
     2.8  \newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''}
     2.9  \newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
    2.10 +\newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
    2.11  \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}}
    2.12  
    2.13  \newsavebox{\notebox}
     3.1 --- a/en/Makefile	Sun Jul 09 21:47:02 2006 -0700
     3.2 +++ b/en/Makefile	Sun Jul 09 21:47:15 2006 -0700
     3.3 @@ -16,6 +16,9 @@
     3.4  example-sources := \
     3.5  	examples/run-example \
     3.6  	examples/mq.qinit-help \
     3.7 +	examples/mq.diff \
     3.8 +	examples/mq.tarball \
     3.9 +	examples/mq.tools \
    3.10  	examples/mq.tutorial
    3.11  
    3.12  latex-options = \
     4.1 Binary file en/examples/data/netplug-1.2.5.tar.bz2 has changed
     5.1 Binary file en/examples/data/netplug-1.2.8.tar.bz2 has changed
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/en/examples/data/remove-redundant-null-checks.patch	Sun Jul 09 21:47:15 2006 -0700
     6.3 @@ -0,0 +1,190 @@
     6.4 +
     6.5 +From: Jesper Juhl <jesper.juhl@gmail.com>
     6.6 +
     6.7 +Remove redundant NULL chck before kfree + tiny CodingStyle cleanup for
     6.8 +drivers/
     6.9 +
    6.10 +Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com>
    6.11 +Signed-off-by: Andrew Morton <akpm@osdl.org>
    6.12 +---
    6.13 +
    6.14 + drivers/char/agp/sgi-agp.c        |    5 ++---
    6.15 + drivers/char/hvcs.c               |   11 +++++------
    6.16 + drivers/message/fusion/mptfc.c    |    6 ++----
    6.17 + drivers/message/fusion/mptsas.c   |    3 +--
    6.18 + drivers/net/fs_enet/fs_enet-mii.c |    3 +--
    6.19 + drivers/net/wireless/ipw2200.c    |   22 ++++++----------------
    6.20 + drivers/scsi/libata-scsi.c        |    4 +---
    6.21 + drivers/video/au1100fb.c          |    3 +--
    6.22 + 8 files changed, 19 insertions(+), 38 deletions(-)
    6.23 +
    6.24 +diff -puN drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/agp/sgi-agp.c
    6.25 +--- a/drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers
    6.26 ++++ a/drivers/char/agp/sgi-agp.c
    6.27 +@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void)
    6.28 + 
    6.29 + static void __devexit agp_sgi_cleanup(void)
    6.30 + {
    6.31 +-	if (sgi_tioca_agp_bridges)
    6.32 +-		kfree(sgi_tioca_agp_bridges);
    6.33 +-	sgi_tioca_agp_bridges=NULL;
    6.34 ++	kfree(sgi_tioca_agp_bridges);
    6.35 ++	sgi_tioca_agp_bridges = NULL;
    6.36 + }
    6.37 + 
    6.38 + module_init(agp_sgi_init);
    6.39 +diff -puN drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/hvcs.c
    6.40 +--- a/drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers
    6.41 ++++ a/drivers/char/hvcs.c
    6.42 +@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = 
    6.43 + static int hvcs_alloc_index_list(int n)
    6.44 + {
    6.45 + 	int i;
    6.46 ++
    6.47 + 	hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
    6.48 + 	if (!hvcs_index_list)
    6.49 + 		return -ENOMEM;
    6.50 + 	hvcs_index_count = n;
    6.51 +-	for(i = 0; i < hvcs_index_count; i++)
    6.52 ++	for (i = 0; i < hvcs_index_count; i++)
    6.53 + 		hvcs_index_list[i] = -1;
    6.54 + 	return 0;
    6.55 + }
    6.56 +@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n)
    6.57 + static void hvcs_free_index_list(void)
    6.58 + {
    6.59 + 	/* Paranoia check to be thorough. */
    6.60 +-	if (hvcs_index_list) {
    6.61 +-		kfree(hvcs_index_list);
    6.62 +-		hvcs_index_list = NULL;
    6.63 +-		hvcs_index_count = 0;
    6.64 +-	}
    6.65 ++	kfree(hvcs_index_list);
    6.66 ++	hvcs_index_list = NULL;
    6.67 ++	hvcs_index_count = 0;
    6.68 + }
    6.69 + 
    6.70 + static int __init hvcs_module_init(void)
    6.71 +diff -puN drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptfc.c
    6.72 +--- a/drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers
    6.73 ++++ a/drivers/message/fusion/mptfc.c
    6.74 +@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in
    6.75 + 	}
    6.76 + 
    6.77 +  out:
    6.78 +-	if (pp0_array)
    6.79 +-		kfree(pp0_array);
    6.80 +-	if (p0_array)
    6.81 +-		kfree(p0_array);
    6.82 ++	kfree(pp0_array);
    6.83 ++	kfree(p0_array);
    6.84 + 	return rc;
    6.85 + }
    6.86 + 
    6.87 +diff -puN drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptsas.c
    6.88 +--- a/drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers
    6.89 ++++ a/drivers/message/fusion/mptsas.c
    6.90 +@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
    6.91 + 	return 0;
    6.92 + 
    6.93 +  out_free_port_info:
    6.94 +-	if (hba)
    6.95 +-		kfree(hba);
    6.96 ++	kfree(hba);
    6.97 +  out:
    6.98 + 	return error;
    6.99 + }
   6.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
   6.101 +--- a/drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers
   6.102 ++++ a/drivers/net/fs_enet/fs_enet-mii.c
   6.103 +@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bu
   6.104 + 	return bus;
   6.105 + 
   6.106 + err:
   6.107 +-	if (bus)
   6.108 +-		kfree(bus);
   6.109 ++	kfree(bus);
   6.110 + 	return ERR_PTR(ret);
   6.111 + }
   6.112 + 
   6.113 +diff -puN drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/wireless/ipw2200.c
   6.114 +--- a/drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers
   6.115 ++++ a/drivers/net/wireless/ipw2200.c
   6.116 +@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_er
   6.117 + 	return error;
   6.118 + }
   6.119 + 
   6.120 +-static void ipw_free_error_log(struct ipw_fw_error *error)
   6.121 +-{
   6.122 +-	if (error)
   6.123 +-		kfree(error);
   6.124 +-}
   6.125 +-
   6.126 + static ssize_t show_event_log(struct device *d,
   6.127 + 			      struct device_attribute *attr, char *buf)
   6.128 + {
   6.129 +@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device
   6.130 + 			   const char *buf, size_t count)
   6.131 + {
   6.132 + 	struct ipw_priv *priv = dev_get_drvdata(d);
   6.133 +-	if (priv->error) {
   6.134 +-		ipw_free_error_log(priv->error);
   6.135 +-		priv->error = NULL;
   6.136 +-	}
   6.137 ++
   6.138 ++	kfree(priv->error);
   6.139 ++	priv->error = NULL;
   6.140 + 	return count;
   6.141 + }
   6.142 + 
   6.143 +@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_p
   6.144 + 				struct ipw_fw_error *error =
   6.145 + 				    ipw_alloc_error_log(priv);
   6.146 + 				ipw_dump_error_log(priv, error);
   6.147 +-				if (error)
   6.148 +-					ipw_free_error_log(error);
   6.149 ++				kfree(error);
   6.150 + 			}
   6.151 + #endif
   6.152 + 		} else {
   6.153 +@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_de
   6.154 + 		}
   6.155 + 	}
   6.156 + 
   6.157 +-	if (priv->error) {
   6.158 +-		ipw_free_error_log(priv->error);
   6.159 +-		priv->error = NULL;
   6.160 +-	}
   6.161 ++	kfree(priv->error);
   6.162 ++	priv->error = NULL;
   6.163 + 
   6.164 + #ifdef CONFIG_IPW2200_PROMISCUOUS
   6.165 + 	ipw_prom_free(priv);
   6.166 +diff -puN drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers drivers/scsi/libata-scsi.c
   6.167 +--- a/drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers
   6.168 ++++ a/drivers/scsi/libata-scsi.c
   6.169 +@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *sc
   6.170 + 	 && copy_to_user(arg + sizeof(args), argbuf, argsize))
   6.171 + 		rc = -EFAULT;
   6.172 + error:
   6.173 +-	if (argbuf)
   6.174 +-		kfree(argbuf);
   6.175 +-
   6.176 ++	kfree(argbuf);
   6.177 + 	return rc;
   6.178 + }
   6.179 + 
   6.180 +diff -puN drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers drivers/video/au1100fb.c
   6.181 +--- a/drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers
   6.182 ++++ a/drivers/video/au1100fb.c
   6.183 +@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void)
   6.184 + {
   6.185 + 	driver_unregister(&au1100fb_driver);
   6.186 + 
   6.187 +-	if (drv_info.opt_mode)
   6.188 +-		kfree(drv_info.opt_mode);
   6.189 ++	kfree(drv_info.opt_mode);
   6.190 + }
   6.191 + 
   6.192 + module_init(au1100fb_init);
   6.193 +_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/en/examples/mq.diff	Sun Jul 09 21:47:15 2006 -0700
     7.3 @@ -0,0 +1,12 @@
     7.4 +#$ name: diff
     7.5 +
     7.6 +echo 'this is my first line' > oldfile
     7.7 +echo 'my first line is here' > newfile
     7.8 +
     7.9 +diff -u oldfile newfile > tiny.patch
    7.10 +
    7.11 +cat tiny.patch
    7.12 +
    7.13 +patch < tiny.patch
    7.14 +
    7.15 +cat newfile
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/en/examples/mq.tarball	Sun Jul 09 21:47:15 2006 -0700
     8.3 @@ -0,0 +1,48 @@
     8.4 +cp $EXAMPLE_DIR/data/netplug-*.tar.bz2 .
     8.5 +ln -s /bin/true download
     8.6 +
     8.7 +#$ name: download
     8.8 +
     8.9 +download netplug-1.2.5.tar.bz2
    8.10 +tar jxf netplug-1.2.5.tar.bz2
    8.11 +cd netplug-1.2.5
    8.12 +hg init
    8.13 +hg commit -q --addremove --message netplug-1.2.5
    8.14 +cd ..
    8.15 +hg clone netplug-1.2.5 netplug
    8.16 +
    8.17 +#$ name:
    8.18 +
    8.19 +cd netplug
    8.20 +echo '[extensions]' >> $HGRC
    8.21 +echo 'hgext.mq =' >> $HGRC
    8.22 +cd ..
    8.23 +
    8.24 +#$ name: qinit
    8.25 +
    8.26 +cd netplug
    8.27 +hg qinit
    8.28 +hg qnew -m 'fix build problem with gcc 4' build-fix.patch
    8.29 +perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c
    8.30 +hg qrefresh
    8.31 +hg tip -p
    8.32 +
    8.33 +#$ name: newsource
    8.34 +
    8.35 +hg qpop -a
    8.36 +cd ..
    8.37 +download netplug-1.2.8.tar.bz2
    8.38 +hg clone netplug-1.2.5 netplug-1.2.8
    8.39 +cd netplug-1.2.8
    8.40 +hg locate -0 | xargs -0 rm
    8.41 +cd ..
    8.42 +tar jxf netplug-1.2.8.tar.bz2
    8.43 +cd netplug-1.2.8
    8.44 +hg commit --addremove --message netplug-1.2.8
    8.45 +
    8.46 +#$ name: repush
    8.47 +
    8.48 +cd ../netplug
    8.49 +hg pull ../netplug-1.2.8
    8.50 +hg qpush -a
    8.51 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/en/examples/mq.tools	Sun Jul 09 21:47:15 2006 -0700
     9.3 @@ -0,0 +1,9 @@
     9.4 +cp $EXAMPLE_DIR/data/remove-redundant-null-checks.patch .
     9.5 +
     9.6 +#$ name: tools
     9.7 +diffstat -p1 remove-redundant-null-checks.patch
     9.8 +
     9.9 +filterdiff -i '*/video/*' remove-redundant-null-checks.patch
    9.10 +
    9.11 +#$ name: lsdiff
    9.12 +lsdiff -nvv remove-redundant-null-checks.patch
    10.1 --- a/en/examples/run-example	Sun Jul 09 21:47:02 2006 -0700
    10.2 +++ b/en/examples/run-example	Sun Jul 09 21:47:15 2006 -0700
    10.3 @@ -76,6 +76,7 @@
    10.4          rcfp = open(rcfile, 'w')
    10.5          print >> rcfp, 'PS1="%s"' % self.prompt
    10.6          print >> rcfp, 'unset HISTFILE'
    10.7 +        print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd()
    10.8          print >> rcfp, 'export LANG=C'
    10.9          print >> rcfp, 'export LC_ALL=C'
   10.10          print >> rcfp, 'export TZ=GMT'
   10.11 @@ -118,7 +119,7 @@
   10.12                          if nl: hunk += '\n'
   10.13                      ofp.write(hunk)
   10.14                      # then its output
   10.15 -                    ofp.write(output)
   10.16 +                    ofp.write(tex_escape(output))
   10.17              self.status('\n')
   10.18          finally:
   10.19              try:
   10.20 @@ -141,7 +142,9 @@
   10.21      for name in os.listdir(path):
   10.22          if name == 'run-example' or name.startswith('.'): continue
   10.23          if name.endswith('.out') or name.endswith('~'): continue
   10.24 -        example(os.path.join(path, name)).run()
   10.25 +        pathname = os.path.join(path, name)
   10.26 +        if os.path.isfile(pathname):
   10.27 +            example(pathname).run()
   10.28      print >> open(os.path.join(path, '.run'), 'w'), time.asctime()
   10.29  
   10.30  if __name__ == '__main__':
    11.1 --- a/en/mq.tex	Sun Jul 09 21:47:02 2006 -0700
    11.2 +++ b/en/mq.tex	Sun Jul 09 21:47:15 2006 -0700
    11.3 @@ -126,6 +126,62 @@
    11.4  Because quilt does not care about revision control tools, it is still
    11.5  a tremendously useful piece of software to know about for situations
    11.6  where you cannot use Mercurial and MQ.
    11.7 +
    11.8 +\section{Understanding patches}
    11.9 +
   11.10 +Because MQ doesn't hide its patch-oriented nature, it is helpful to
   11.11 +understand what patches are, and a little about the tools that work
   11.12 +with them.
   11.13 +
   11.14 +The traditional Unix \command{diff} command compares two files, and
   11.15 +prints a list of differences between them. The \command{patch} command
   11.16 +understands these differences as \emph{modifications} to make to a
   11.17 +file.  Take a look at figure~\ref{ex:mq:diff} for a simple example of
   11.18 +these commands in action.
   11.19 +
   11.20 +\begin{figure}[ht]
   11.21 +  \interaction{mq.diff.diff}
   11.22 +  \caption{Simple uses of the \command{diff} and \command{patch} commands}
   11.23 +  \label{ex:mq:diff}
   11.24 +\end{figure}
   11.25 +
   11.26 +The type of file that \command{diff} generates (and \command{patch}
   11.27 +takes as input) is called a ``patch'' or a ``diff''; there is no
   11.28 +difference between a patch and a diff.  (We'll use the term ``patch'',
   11.29 +since it's more commonly used.)
   11.30 +
   11.31 +A patch file can start with arbitrary text; the \command{patch}
   11.32 +command ignores this text, but MQ uses it as the commit message when
   11.33 +creating changesets.  To find the beginning of the patch content,
   11.34 +\command{patch} searches for the first line that starts with the
   11.35 +string ``\texttt{diff~-}''.
   11.36 +
   11.37 +MQ works with \emph{unified} diffs (\command{patch} can accept several
   11.38 +other diff formats, but MQ doesn't).  A unified diff contains two
   11.39 +kinds of header.  The \emph{file header} describes the file being
   11.40 +modified; it contains the name of the file to modify.  When
   11.41 +\command{patch} sees a new file header, it looks for a file with that
   11.42 +name to start modifying.
   11.43 +
   11.44 +After the file header comes a series of \emph{hunks}.  Each hunk
   11.45 +starts with a header; this identifies the range of line numbers within
   11.46 +the file that the hunk should modify.  Following the header, a hunk
   11.47 +starts and ends with a few (usually three) lines of text from the
   11.48 +unmodified file; these are called the \emph{context} for the hunk.  If
   11.49 +there's only a small amount of context between successive hunks,
   11.50 +\command{diff} doesn't print a new hunk header; it just runs the hunks
   11.51 +together, with a few lines of context between modifications.
   11.52 +
   11.53 +Each line of context begins with a space character.  Within the hunk,
   11.54 +a line that begins with ``\texttt{-}'' means ``remove this line,''
   11.55 +while a line that begins with ``\texttt{+}'' means ``insert this
   11.56 +line.''  For example, a line that is modified is represented by one
   11.57 +deletion and one insertion.
   11.58 +
   11.59 +We will return to ome of the more subtle aspects of patches later (in
   11.60 +section~\ref{ex:mq:adv-patch}), but you should have enough information
   11.61 +now to use MQ.
   11.62 +
   11.63  \section{Getting started with Mercurial Queues}
   11.64  \label{sec:mq:start}
   11.65  
   11.66 @@ -200,6 +256,7 @@
   11.67  working directory as you usually would.  All of the normal Mercurial
   11.68  commands, such as \hgcmd{diff} and \hgcmd{annotate}, work exactly as
   11.69  they did before.
   11.70 +
   11.71  \subsection{Refreshing a patch}
   11.72  
   11.73  When you reach a point where you want to save your work, use the
   11.74 @@ -319,45 +376,12 @@
   11.75  \hgcmd{qrefresh} the core patch, and \hgcmd{qpush} back to the UI
   11.76  patch to continue where you left off.
   11.77  
   11.78 -\section{Mercurial Queues and GNU patch}
   11.79 -\label{sec:mq:patch}
   11.80 -
   11.81 -MQ uses the GNU \command{patch} command to apply patches.  Because MQ
   11.82 -doesn't hide its patch-oriented nature, it is helpful to understand
   11.83 -the data that MQ and \command{patch} work with, and a few aspects of
   11.84 -how \command{patch} operates.
   11.85 -
   11.86 -The \command{diff} command generates a list of modifications by
   11.87 -comparing two files.  The \command{patch} command applies a list of
   11.88 -modifications to a file.  The kinds of files that \command{diff} and
   11.89 -\command{patch} work with are referred to as both ``diffs'' and
   11.90 -``patches;'' there is no difference between a diff and a patch.
   11.91 -
   11.92 -A patch file can start with arbitrary text; MQ uses this text as the
   11.93 -commit message when creating changesets.  It treats the first line
   11.94 -that starts with the string ``\texttt{diff~-}'' as the separator
   11.95 -between header and content.
   11.96 -
   11.97 -MQ works with \emph{unified} diffs (\command{patch} can accept several
   11.98 -other diff formats, but MQ doesn't).  A unified diff contains two
   11.99 -kinds of header.  The \emph{file header} describes the file being
  11.100 -modified; it contains the name of the file to modify.  When
  11.101 -\command{patch} sees a new file header, it looks for a file with that
  11.102 -name to start modifying.
  11.103 -
  11.104 -After the file header comes a series of \emph{hunks}.  Each hunk
  11.105 -starts with a header; this identifies the range of line numbers within
  11.106 -the file that the hunk should modify.  Following the header, a hunk
  11.107 -starts and ends with a few (usually three) lines of text from the
  11.108 -unmodified file; these are called the \emph{context} for the hunk.
  11.109 -Each unmodified line begins with a space characters.  Within the hunk,
  11.110 -a line that begins with ``\texttt{-}'' means ``remove this line,''
  11.111 -while a line that begins with ``\texttt{+}'' means ``insert this
  11.112 -line.''  For example, a line that is modified is represented by one
  11.113 -deletion and one insertion.
  11.114 -
  11.115 -The \command{diff} command runs hunks together when there's not enough
  11.116 -context between modifications to justify
  11.117 +\section{More about patches}
  11.118 +\label{sec:mq:adv-patch}
  11.119 +
  11.120 +MQ uses the GNU \command{patch} command to apply patches, so it's
  11.121 +helpful to know about a few more detailed aspects of how
  11.122 +\command{patch} works.
  11.123  
  11.124  When \command{patch} applies a hunk, it tries a handful of
  11.125  successively less accurate strategies to try to make the hunk apply.
  11.126 @@ -622,6 +646,7 @@
  11.127  confuse MQ's idea of which patches are applied.
  11.128  
  11.129  \section{Commands for working with patches}
  11.130 +\label{sec:mq:tools}
  11.131  
  11.132  Once you've been working with patches for a while, you'll find
  11.133  yourself hungry for tools that will help you to understand and
  11.134 @@ -636,6 +661,12 @@
  11.135  do clever things with prefixes of file names that inevitably confuse
  11.136  at least me.)
  11.137  
  11.138 +\begin{figure}[ht]
  11.139 +  \interaction{mq.tools.tools}
  11.140 +  \caption{The \command{diffstat}, \command{filterdiff}, and \command{lsdiff} commands}
  11.141 +  \label{ex:mq:tools}
  11.142 +\end{figure}
  11.143 +
  11.144  The \package{patchutils} package~\cite{web:patchutils} is invaluable.
  11.145  It provides a set of small utilities that follow the ``Unix
  11.146  philosophy;'' each does one useful thing with a patch.  The
  11.147 @@ -645,6 +676,122 @@
  11.148  invocation of \command{filterdiff} can generate a smaller patch that
  11.149  only touches files whose names match a particular glob pattern.
  11.150  
  11.151 +\section{Good ways to work with patches}
  11.152 +
  11.153 +Whether you are working on a patch series to submit to a free software
  11.154 +or open source project, or a series that you intend to treat as a
  11.155 +sequence of regular changesets when you're done, you can use some
  11.156 +simple techniques to keep your work well organised.
  11.157 +
  11.158 +Give your patches descriptive names.  A good name for a patch might be
  11.159 +\filename{rework-device-alloc.patch}, because it will immediately give
  11.160 +you a hint what the purpose of the patch is.  Long names shouldn't be
  11.161 +a problem; you won't be typing the names often, but you \emph{will} be
  11.162 +running commands like \hgcmd{qapplied} and \hgcmd{qtop} over and over.
  11.163 +Good naming becomes especially important when you have a number of
  11.164 +patches to work with, or if you are juggling a number of different
  11.165 +tasks and your patches only get a fraction of your attention.
  11.166 +
  11.167 +Be aware of what patch you're working on.  Use the \hgcmd{qtop}
  11.168 +command and skim over the text of your patches frequently---for
  11.169 +example, using \hgcmdargs{tip}{\hgopt{tip}{-p}})---to be sure of where
  11.170 +you stand.  I have several times worked on and \hgcmd{qrefresh}ed a
  11.171 +patch other than the one I intended, and it's often tricky to migrate
  11.172 +changes into the right patch after making them in the wrong one.
  11.173 +
  11.174 +For this reason, it is very much worth investing a little time to
  11.175 +learn how to use some of the third-party tools I described in
  11.176 +section~\ref{sec:mq:tools}, particularly \command{diffstat} and
  11.177 +\command{filterdiff}.  The former will give you a quick idea of what
  11.178 +changes your patch is making, while the latter makes it easy to splice
  11.179 +hunks selectively out of one patch and into another.
  11.180 +
  11.181 +\section{MQ cookbook}
  11.182 +
  11.183 +\subsection{Manage ``trivial'' patches}
  11.184 +
  11.185 +Because the overhead of dropping files into a new Mercurial repository
  11.186 +is so low, it makes a lot of sense to manage patches this way even if
  11.187 +you simply want to make a few changes to a source tarball that you
  11.188 +downloaded.
  11.189 +
  11.190 +Begin by downloading and unpacking the source tarball,
  11.191 +and turning it into a Mercurial repository.
  11.192 +\interaction{mq.tarball.download}
  11.193 +
  11.194 +Continue by creating a patch stack and making your changes.
  11.195 +\interaction{mq.tarball.qinit}
  11.196 +
  11.197 +Let's say a few weeks or months pass, and your package author releases
  11.198 +a new version.  First, bring their changes into the repository.
  11.199 +\interaction{mq.tarball.newsource}
  11.200 +The pipeline starting with \hgcmd{locate} above deletes all files in
  11.201 +the working directory, so that \hgcmd{commit}'s
  11.202 +\hgopt{commit}{--addremove} option can actually tell which files have
  11.203 +really been removed in the newer version of the source.
  11.204 +
  11.205 +Finally, you can apply your patches on top of the new tree.
  11.206 +\interaction{mq.tarball.repush}
  11.207 +
  11.208 +\subsection{Combining entire patches}
  11.209 +\label{sec:mq:combine}
  11.210 +
  11.211 +It's easy to combine entire patches.
  11.212 +
  11.213 +\begin{enumerate}
  11.214 +\item \hgcmd{qpop} your applied patches until neither patch is
  11.215 +  applied.
  11.216 +\item Concatenate the patches that you want to combine together:
  11.217 +  \begin{codesample4}
  11.218 +    cat patch-to-drop.patch >> patch-to-augment.patch
  11.219 +  \end{codesample4}
  11.220 +  The description from the first patch (if you have one) will be used
  11.221 +  as the commit comment when you \hgcmd{qpush} the combined patch.
  11.222 +  Edit the patch description if you need to.
  11.223 +\item Use the \hgcmd{qdel} command to delete the patch you're dropping
  11.224 +  from the \sfilename{series} file.
  11.225 +\item \hgcmd{qpush} the combined patch.  Fix up any rejects.
  11.226 +\item \hgcmd{qrefresh} the combined patch to tidy it up.
  11.227 +\end{enumerate}
  11.228 +
  11.229 +\subsection{Merging part of one patch into another}
  11.230 +
  11.231 +Merging \emph{part} of one patch into another is more difficult than
  11.232 +combining entire patches.
  11.233 +
  11.234 +If you want to move changes to entire files, you can use
  11.235 +\command{filterdiff}'s \cmdopt{filterdiff}{-i} and
  11.236 +\cmdopt{filterdiff}{-x} options to choose the modifications to snip
  11.237 +out of one patch, concatenating its output onto the end of the patch
  11.238 +you want to merge into.  You usually won't need to modify the patch
  11.239 +you've merged the changes from.  Instead, MQ will report some rejected
  11.240 +hunks when you \hgcmd{qpush} it (from the hunks you moved into the
  11.241 +other patch), and you can simply \hgcmd{qrefresh} the patch to drop
  11.242 +the duplicate hunks.
  11.243 +
  11.244 +If you have a patch that has multiple hunks modifying a file, and you
  11.245 +only want to move a few of those hunks, the job becomes more messy,
  11.246 +but you can still partly automate it.  Use \cmdargs{lsdiff}{-nvv} to
  11.247 +print some metadata about the patch.
  11.248 +\interaction{mq.tools.lsdiff}
  11.249 +
  11.250 +This command prints three different kinds of number:
  11.251 +\begin{itemize}
  11.252 +\item a \emph{file number} to identify each file modified in the patch;
  11.253 +\item the line number within a modified file that a hunk starts at; and
  11.254 +\item a \emph{hunk number} to identify that hunk.
  11.255 +\end{itemize}
  11.256 +
  11.257 +You'll have to use some visual inspection, and reading of the patch,
  11.258 +to identify the file and hunk numbers you'll want, but you can then
  11.259 +pass them to to \command{filterdiff}'s \cmdopt{filterdiff}{--files}
  11.260 +and \cmdopt{filterdiff}{--hunks} options, to select exactly the file
  11.261 +and hunk you want to extract.
  11.262 +
  11.263 +Once you have this hunk, you can concatenate it onto the end of your
  11.264 +destination patch and continue with the remainder of
  11.265 +section~\ref{sec:mq:combine}.
  11.266 +
  11.267  %%% Local Variables: 
  11.268  %%% mode: latex
  11.269  %%% TeX-master: "00book"