view en/tour-merge.tex @ 102:ff9dc8bc2a8b

More. Merge. Stuff.
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 18 Oct 2006 15:47:04 -0700
parents 321732566ac1
children 5b80c922ebdd
line wrap: on
line source

\chapter{A tour of Mercurial: merging work}
\label{chap:tour-merge}

We've now covered cloning a repository, making changes in a
repository, and pulling or pushing changes from one repository into
another.  Our next step is \emph{merging} changes from separate
repositories.

\section{Merging streams of work}

Merging is a fundamental part of working with a distributed revision
control tool.
\begin{itemize}
\item Alice and Bob each have a personal copy of a repository for a
  project they're collaborating on.  Alice fixes a bug in her
  repository; Bob adds a new feature in his.  They want the shared
  repository to contain both the bug fix and the new feature.
\item I frequently work on several different tasks for a single
  project at once, each safely isolated in its own repository.
  Working this way means that I often need to merge one piece of my
  own work with another.
\end{itemize}

Because merging is such a common thing to need to do, Mercurial makes
it easy.  Let's walk through the process.  We'll begin by cloning yet
another repository (see how often they spring up?) and making a change
in it.
\interaction{tour.merge.clone}
We should now have two copies of \filename{hello.c} with different
contents.  The histories of the two repositories have also diverged,
as illustrated in figure~\ref{fig:tour-merge:sep-repos}.
\interaction{tour.merge.cat}

\begin{figure}[ht]
  \centering
  \grafix{tour-merge-sep-repos}
  \caption{Divergent recent histories of the \dirname{my-hello} and
    \dirname{my-new-hello} repositories}
  \label{fig:tour-merge:sep-repos}
\end{figure}

We already know that pulling changes from our \dirname{my-hello}
repository will have no effect on the working directory.
\interaction{tour.merge.pull}
However, the \hgcmd{pull} command says something about ``heads''.  

\subsection{Head changesets}

A head is a change that has no descendants, or children, as they're
also known.  The tip revision is thus a head, because the newest
revision in a repository doesn't have any children, but a repository
can contain more than one head.

\begin{figure}[ht]
  \centering
  \grafix{tour-merge-pull}
  \caption{Repository contents after pulling from \dirname{my-hello} into
    \dirname{my-new-hello}}
  \label{fig:tour-merge:pull}
\end{figure}

In figure~\ref{fig:tour-merge:pull}, you can see the effect of the
pull from \dirname{my-hello} into \dirname{my-new-hello}.  The history
that was already present in \dirname{my-new-hello} is untouched, but a
new revision has been added.  By referring to
figure~\ref{fig:tour-merge:sep-repos}, we can see that the
\emph{changeset ID} remains the same in the new repository, but the
\emph{revision number} has changed.  (This, incidentally, is a fine
example of why it's not safe to use revision numbers when discussing
changesets.)  We can view the heads in a repository using the
\hgcmd{heads} command.
\interaction{tour.merge.heads}

\subsection{Performing the merge}

What happens if we try to use the normal \hgcmd{update} command to
update to the new tip?
\interaction{tour.merge.update}
Mercurial is telling us that the \hgcmd{update} command won't do a
merge; it won't update the working directory when it thinks we might
be wanting to do a merge, unless we force it to do so.  Instead, we
use the \hgcmd{merge} command to merge the two heads.
\interaction{tour.merge.merge}

\begin{figure}[ht]
  \centering
  \grafix{tour-merge-merge}
  \caption{Working directory and repository during merge, and
    following commit}
  \label{fig:tour-merge:merge}
\end{figure}

This updates the working directory so that it contains changes from
\emph{both} heads, which is reflected in both the output of
\hgcmd{parents} and the contents of \filename{hello.c}.
\interaction{tour.merge.parents}

\subsection{Committing the results of the merge}

Whenever we've done a merge, \hgcmd{parents} will display two parents
until we \hgcmd{commit} the results of the merge.
\interaction{tour.merge.commit}
We now have a new tip revision; notice that it has \emph{both} of
our former heads as its parents.  These are the same revisions that
were previously displayed by \hgcmd{parents}.
\interaction{tour.merge.tip}
In figure~\ref{fig:tour-merge:merge}, you can see a representation of
what happens to the working directory during the merge, and how this
affects the repository when the commit happens.  During the merge, the
working directory has two parent changesets, and these become the
parents of the new changeset.

\section{Merging conflicting changes}

Most merges are simple affairs, but sometimes you'll find yourself
merging a change that you made with another, where both modify the
same portions of the same files.  Unless both modifications are
identical, this results in a \emph{conflict}, where you have to decide
how to reconcile the different changes into something coherent.

\section{Using an extension to simplify merging}

The process of merging changes as outlined above is straightforward,
but requires running three commands in sequence.
\begin{codesample2}
  hg pull
  hg merge
  hg commit -m 'Merged remote changes'
\end{codesample2}
In the case of the final commit, you also need to come up with a
commit message, which is almost always going to be a piece of
uninteresting ``boilerplate'' text.

It would be nice to reduce the number of steps needed, if this were
possible.  Indeed, Mercurial is distributed with an extension called
\hgext{fetch} that does just this.

Mercurial provides a flexible extension mechanism that lets people
extend its functionality, while keeping the core of Mercurial small
and easy to deal with.  Some extensions add new commands that you can
use from the command line, while others work ``behind the scenes,''
for example adding capabilities to the server.

The \hgext{fetch} extension adds a new command called, not
surprisingly, \hgcmd{fetch}.  This extension acts as a combination of
\hgcmd{pull}, \hgcmd{update} and \hgcmd{merge}.  It begins by pulling
changes from another repository into the current repository.  If it
finds that the changes added a new head to the repository, it begins a
merge, then commits the result of the merge with an
automatically-generated commit message.  If no new heads were added,
it updates the working directory to the new tip changeset.

Enabling the \hgext{fetch} extension is easy.  Edit your
\sfilename{.hgrc}, and either go to the \rcsection{extensions} section
or create an \rcsection{extensions} section.  Then add a line that
simply reads ``\Verb+fetch +''.
\begin{codesample2}
  [extensions]
  fetch =
\end{codesample2}
(Normally, on the right-hand side of the ``\texttt{=}'' would appear
the location of the extension, but since the \hgext{fetch} extension
is in the standard distribution, Mercurial knows where to search for
it.)

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "00book"
%%% End: