diff en/mq.tex @ 19:187702df428b

Piles of new content for MQ chapter - cookbook stuff.
author Bryan O'Sullivan <bos@serpentine.com>
date Fri, 07 Jul 2006 19:56:53 -0700
parents e6f4088ebe52
children 9d5b6d303ef5
line wrap: on
line diff
--- a/en/mq.tex	Tue Jul 04 16:41:31 2006 -0700
+++ b/en/mq.tex	Fri Jul 07 19:56:53 2006 -0700
@@ -126,6 +126,62 @@
 Because quilt does not care about revision control tools, it is still
 a tremendously useful piece of software to know about for situations
 where you cannot use Mercurial and MQ.
+
+\section{Understanding patches}
+
+Because MQ doesn't hide its patch-oriented nature, it is helpful to
+understand what patches are, and a little about the tools that work
+with them.
+
+The traditional Unix \command{diff} command compares two files, and
+prints a list of differences between them. The \command{patch} command
+understands these differences as \emph{modifications} to make to a
+file.  Take a look at figure~\ref{ex:mq:diff} for a simple example of
+these commands in action.
+
+\begin{figure}[ht]
+  \interaction{mq.diff.diff}
+  \caption{Simple uses of the \command{diff} and \command{patch} commands}
+  \label{ex:mq:diff}
+\end{figure}
+
+The type of file that \command{diff} generates (and \command{patch}
+takes as input) is called a ``patch'' or a ``diff''; there is no
+difference between a patch and a diff.  (We'll use the term ``patch'',
+since it's more commonly used.)
+
+A patch file can start with arbitrary text; the \command{patch}
+command ignores this text, but MQ uses it as the commit message when
+creating changesets.  To find the beginning of the patch content,
+\command{patch} searches for the first line that starts with the
+string ``\texttt{diff~-}''.
+
+MQ works with \emph{unified} diffs (\command{patch} can accept several
+other diff formats, but MQ doesn't).  A unified diff contains two
+kinds of header.  The \emph{file header} describes the file being
+modified; it contains the name of the file to modify.  When
+\command{patch} sees a new file header, it looks for a file with that
+name to start modifying.
+
+After the file header comes a series of \emph{hunks}.  Each hunk
+starts with a header; this identifies the range of line numbers within
+the file that the hunk should modify.  Following the header, a hunk
+starts and ends with a few (usually three) lines of text from the
+unmodified file; these are called the \emph{context} for the hunk.  If
+there's only a small amount of context between successive hunks,
+\command{diff} doesn't print a new hunk header; it just runs the hunks
+together, with a few lines of context between modifications.
+
+Each line of context begins with a space character.  Within the hunk,
+a line that begins with ``\texttt{-}'' means ``remove this line,''
+while a line that begins with ``\texttt{+}'' means ``insert this
+line.''  For example, a line that is modified is represented by one
+deletion and one insertion.
+
+We will return to ome of the more subtle aspects of patches later (in
+section~\ref{ex:mq:adv-patch}), but you should have enough information
+now to use MQ.
+
 \section{Getting started with Mercurial Queues}
 \label{sec:mq:start}
 
@@ -200,6 +256,7 @@
 working directory as you usually would.  All of the normal Mercurial
 commands, such as \hgcmd{diff} and \hgcmd{annotate}, work exactly as
 they did before.
+
 \subsection{Refreshing a patch}
 
 When you reach a point where you want to save your work, use the
@@ -319,45 +376,12 @@
 \hgcmd{qrefresh} the core patch, and \hgcmd{qpush} back to the UI
 patch to continue where you left off.
 
-\section{Mercurial Queues and GNU patch}
-\label{sec:mq:patch}
-
-MQ uses the GNU \command{patch} command to apply patches.  Because MQ
-doesn't hide its patch-oriented nature, it is helpful to understand
-the data that MQ and \command{patch} work with, and a few aspects of
-how \command{patch} operates.
-
-The \command{diff} command generates a list of modifications by
-comparing two files.  The \command{patch} command applies a list of
-modifications to a file.  The kinds of files that \command{diff} and
-\command{patch} work with are referred to as both ``diffs'' and
-``patches;'' there is no difference between a diff and a patch.
-
-A patch file can start with arbitrary text; MQ uses this text as the
-commit message when creating changesets.  It treats the first line
-that starts with the string ``\texttt{diff~-}'' as the separator
-between header and content.
+\section{More about patches}
+\label{sec:mq:adv-patch}
 
-MQ works with \emph{unified} diffs (\command{patch} can accept several
-other diff formats, but MQ doesn't).  A unified diff contains two
-kinds of header.  The \emph{file header} describes the file being
-modified; it contains the name of the file to modify.  When
-\command{patch} sees a new file header, it looks for a file with that
-name to start modifying.
-
-After the file header comes a series of \emph{hunks}.  Each hunk
-starts with a header; this identifies the range of line numbers within
-the file that the hunk should modify.  Following the header, a hunk
-starts and ends with a few (usually three) lines of text from the
-unmodified file; these are called the \emph{context} for the hunk.
-Each unmodified line begins with a space characters.  Within the hunk,
-a line that begins with ``\texttt{-}'' means ``remove this line,''
-while a line that begins with ``\texttt{+}'' means ``insert this
-line.''  For example, a line that is modified is represented by one
-deletion and one insertion.
-
-The \command{diff} command runs hunks together when there's not enough
-context between modifications to justify
+MQ uses the GNU \command{patch} command to apply patches, so it's
+helpful to know about a few more detailed aspects of how
+\command{patch} works.
 
 When \command{patch} applies a hunk, it tries a handful of
 successively less accurate strategies to try to make the hunk apply.
@@ -622,6 +646,7 @@
 confuse MQ's idea of which patches are applied.
 
 \section{Commands for working with patches}
+\label{sec:mq:tools}
 
 Once you've been working with patches for a while, you'll find
 yourself hungry for tools that will help you to understand and
@@ -636,6 +661,12 @@
 do clever things with prefixes of file names that inevitably confuse
 at least me.)
 
+\begin{figure}[ht]
+  \interaction{mq.tools.tools}
+  \caption{The \command{diffstat}, \command{filterdiff}, and \command{lsdiff} commands}
+  \label{ex:mq:tools}
+\end{figure}
+
 The \package{patchutils} package~\cite{web:patchutils} is invaluable.
 It provides a set of small utilities that follow the ``Unix
 philosophy;'' each does one useful thing with a patch.  The
@@ -645,6 +676,122 @@
 invocation of \command{filterdiff} can generate a smaller patch that
 only touches files whose names match a particular glob pattern.
 
+\section{Good ways to work with patches}
+
+Whether you are working on a patch series to submit to a free software
+or open source project, or a series that you intend to treat as a
+sequence of regular changesets when you're done, you can use some
+simple techniques to keep your work well organised.
+
+Give your patches descriptive names.  A good name for a patch might be
+\filename{rework-device-alloc.patch}, because it will immediately give
+you a hint what the purpose of the patch is.  Long names shouldn't be
+a problem; you won't be typing the names often, but you \emph{will} be
+running commands like \hgcmd{qapplied} and \hgcmd{qtop} over and over.
+Good naming becomes especially important when you have a number of
+patches to work with, or if you are juggling a number of different
+tasks and your patches only get a fraction of your attention.
+
+Be aware of what patch you're working on.  Use the \hgcmd{qtop}
+command and skim over the text of your patches frequently---for
+example, using \hgcmdargs{tip}{\hgopt{tip}{-p}})---to be sure of where
+you stand.  I have several times worked on and \hgcmd{qrefresh}ed a
+patch other than the one I intended, and it's often tricky to migrate
+changes into the right patch after making them in the wrong one.
+
+For this reason, it is very much worth investing a little time to
+learn how to use some of the third-party tools I described in
+section~\ref{sec:mq:tools}, particularly \command{diffstat} and
+\command{filterdiff}.  The former will give you a quick idea of what
+changes your patch is making, while the latter makes it easy to splice
+hunks selectively out of one patch and into another.
+
+\section{MQ cookbook}
+
+\subsection{Manage ``trivial'' patches}
+
+Because the overhead of dropping files into a new Mercurial repository
+is so low, it makes a lot of sense to manage patches this way even if
+you simply want to make a few changes to a source tarball that you
+downloaded.
+
+Begin by downloading and unpacking the source tarball,
+and turning it into a Mercurial repository.
+\interaction{mq.tarball.download}
+
+Continue by creating a patch stack and making your changes.
+\interaction{mq.tarball.qinit}
+
+Let's say a few weeks or months pass, and your package author releases
+a new version.  First, bring their changes into the repository.
+\interaction{mq.tarball.newsource}
+The pipeline starting with \hgcmd{locate} above deletes all files in
+the working directory, so that \hgcmd{commit}'s
+\hgopt{commit}{--addremove} option can actually tell which files have
+really been removed in the newer version of the source.
+
+Finally, you can apply your patches on top of the new tree.
+\interaction{mq.tarball.repush}
+
+\subsection{Combining entire patches}
+\label{sec:mq:combine}
+
+It's easy to combine entire patches.
+
+\begin{enumerate}
+\item \hgcmd{qpop} your applied patches until neither patch is
+  applied.
+\item Concatenate the patches that you want to combine together:
+  \begin{codesample4}
+    cat patch-to-drop.patch >> patch-to-augment.patch
+  \end{codesample4}
+  The description from the first patch (if you have one) will be used
+  as the commit comment when you \hgcmd{qpush} the combined patch.
+  Edit the patch description if you need to.
+\item Use the \hgcmd{qdel} command to delete the patch you're dropping
+  from the \sfilename{series} file.
+\item \hgcmd{qpush} the combined patch.  Fix up any rejects.
+\item \hgcmd{qrefresh} the combined patch to tidy it up.
+\end{enumerate}
+
+\subsection{Merging part of one patch into another}
+
+Merging \emph{part} of one patch into another is more difficult than
+combining entire patches.
+
+If you want to move changes to entire files, you can use
+\command{filterdiff}'s \cmdopt{filterdiff}{-i} and
+\cmdopt{filterdiff}{-x} options to choose the modifications to snip
+out of one patch, concatenating its output onto the end of the patch
+you want to merge into.  You usually won't need to modify the patch
+you've merged the changes from.  Instead, MQ will report some rejected
+hunks when you \hgcmd{qpush} it (from the hunks you moved into the
+other patch), and you can simply \hgcmd{qrefresh} the patch to drop
+the duplicate hunks.
+
+If you have a patch that has multiple hunks modifying a file, and you
+only want to move a few of those hunks, the job becomes more messy,
+but you can still partly automate it.  Use \cmdargs{lsdiff}{-nvv} to
+print some metadata about the patch.
+\interaction{mq.tools.lsdiff}
+
+This command prints three different kinds of number:
+\begin{itemize}
+\item a \emph{file number} to identify each file modified in the patch;
+\item the line number within a modified file that a hunk starts at; and
+\item a \emph{hunk number} to identify that hunk.
+\end{itemize}
+
+You'll have to use some visual inspection, and reading of the patch,
+to identify the file and hunk numbers you'll want, but you can then
+pass them to to \command{filterdiff}'s \cmdopt{filterdiff}{--files}
+and \cmdopt{filterdiff}{--hunks} options, to select exactly the file
+and hunk you want to extract.
+
+Once you have this hunk, you can concatenate it onto the end of your
+destination patch and continue with the remainder of
+section~\ref{sec:mq:combine}.
+
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "00book"