jerojasro@336: \chapter{A tour of Mercurial: merging work} jerojasro@336: \label{chap:tour-merge} jerojasro@336: jerojasro@336: We've now covered cloning a repository, making changes in a jerojasro@336: repository, and pulling or pushing changes from one repository into jerojasro@336: another. Our next step is \emph{merging} changes from separate jerojasro@336: repositories. jerojasro@336: jerojasro@336: \section{Merging streams of work} jerojasro@336: jerojasro@336: Merging is a fundamental part of working with a distributed revision jerojasro@336: control tool. jerojasro@336: \begin{itemize} jerojasro@336: \item Alice and Bob each have a personal copy of a repository for a jerojasro@336: project they're collaborating on. Alice fixes a bug in her jerojasro@336: repository; Bob adds a new feature in his. They want the shared jerojasro@336: repository to contain both the bug fix and the new feature. jerojasro@336: \item I frequently work on several different tasks for a single jerojasro@336: project at once, each safely isolated in its own repository. jerojasro@336: Working this way means that I often need to merge one piece of my jerojasro@336: own work with another. jerojasro@336: \end{itemize} jerojasro@336: jerojasro@336: Because merging is such a common thing to need to do, Mercurial makes jerojasro@336: it easy. Let's walk through the process. We'll begin by cloning yet jerojasro@336: another repository (see how often they spring up?) and making a change jerojasro@336: in it. jerojasro@336: \interaction{tour.merge.clone} jerojasro@336: We should now have two copies of \filename{hello.c} with different jerojasro@336: contents. The histories of the two repositories have also diverged, jerojasro@336: as illustrated in figure~\ref{fig:tour-merge:sep-repos}. jerojasro@336: \interaction{tour.merge.cat} jerojasro@336: jerojasro@336: \begin{figure}[ht] jerojasro@336: \centering jerojasro@336: \grafix{tour-merge-sep-repos} jerojasro@336: \caption{Divergent recent histories of the \dirname{my-hello} and jerojasro@336: \dirname{my-new-hello} repositories} jerojasro@336: \label{fig:tour-merge:sep-repos} jerojasro@336: \end{figure} jerojasro@336: jerojasro@336: We already know that pulling changes from our \dirname{my-hello} jerojasro@336: repository will have no effect on the working directory. jerojasro@336: \interaction{tour.merge.pull} jerojasro@336: However, the \hgcmd{pull} command says something about ``heads''. jerojasro@336: jerojasro@336: \subsection{Head changesets} jerojasro@336: jerojasro@336: A head is a change that has no descendants, or children, as they're jerojasro@336: also known. The tip revision is thus a head, because the newest jerojasro@336: revision in a repository doesn't have any children, but a repository jerojasro@336: can contain more than one head. jerojasro@336: jerojasro@336: \begin{figure}[ht] jerojasro@336: \centering jerojasro@336: \grafix{tour-merge-pull} jerojasro@336: \caption{Repository contents after pulling from \dirname{my-hello} into jerojasro@336: \dirname{my-new-hello}} jerojasro@336: \label{fig:tour-merge:pull} jerojasro@336: \end{figure} jerojasro@336: jerojasro@336: In figure~\ref{fig:tour-merge:pull}, you can see the effect of the jerojasro@336: pull from \dirname{my-hello} into \dirname{my-new-hello}. The history jerojasro@336: that was already present in \dirname{my-new-hello} is untouched, but a jerojasro@336: new revision has been added. By referring to jerojasro@336: figure~\ref{fig:tour-merge:sep-repos}, we can see that the jerojasro@336: \emph{changeset ID} remains the same in the new repository, but the jerojasro@336: \emph{revision number} has changed. (This, incidentally, is a fine jerojasro@336: example of why it's not safe to use revision numbers when discussing jerojasro@336: changesets.) We can view the heads in a repository using the jerojasro@336: \hgcmd{heads} command. jerojasro@336: \interaction{tour.merge.heads} jerojasro@336: jerojasro@336: \subsection{Performing the merge} jerojasro@336: jerojasro@336: What happens if we try to use the normal \hgcmd{update} command to jerojasro@336: update to the new tip? jerojasro@336: \interaction{tour.merge.update} jerojasro@336: Mercurial is telling us that the \hgcmd{update} command won't do a jerojasro@336: merge; it won't update the working directory when it thinks we might jerojasro@336: be wanting to do a merge, unless we force it to do so. Instead, we jerojasro@336: use the \hgcmd{merge} command to merge the two heads. jerojasro@336: \interaction{tour.merge.merge} jerojasro@336: jerojasro@336: \begin{figure}[ht] jerojasro@336: \centering jerojasro@336: \grafix{tour-merge-merge} jerojasro@336: \caption{Working directory and repository during merge, and jerojasro@336: following commit} jerojasro@336: \label{fig:tour-merge:merge} jerojasro@336: \end{figure} jerojasro@336: jerojasro@336: This updates the working directory so that it contains changes from jerojasro@336: \emph{both} heads, which is reflected in both the output of jerojasro@336: \hgcmd{parents} and the contents of \filename{hello.c}. jerojasro@336: \interaction{tour.merge.parents} jerojasro@336: jerojasro@336: \subsection{Committing the results of the merge} jerojasro@336: jerojasro@336: Whenever we've done a merge, \hgcmd{parents} will display two parents jerojasro@336: until we \hgcmd{commit} the results of the merge. jerojasro@336: \interaction{tour.merge.commit} jerojasro@336: We now have a new tip revision; notice that it has \emph{both} of jerojasro@336: our former heads as its parents. These are the same revisions that jerojasro@336: were previously displayed by \hgcmd{parents}. jerojasro@336: \interaction{tour.merge.tip} jerojasro@336: In figure~\ref{fig:tour-merge:merge}, you can see a representation of jerojasro@336: what happens to the working directory during the merge, and how this jerojasro@336: affects the repository when the commit happens. During the merge, the jerojasro@336: working directory has two parent changesets, and these become the jerojasro@336: parents of the new changeset. jerojasro@336: jerojasro@336: \section{Merging conflicting changes} jerojasro@336: jerojasro@336: Most merges are simple affairs, but sometimes you'll find yourself jerojasro@336: merging changes where each modifies the same portions of the same jerojasro@336: files. Unless both modifications are identical, this results in a jerojasro@336: \emph{conflict}, where you have to decide how to reconcile the jerojasro@336: different changes into something coherent. jerojasro@336: jerojasro@336: \begin{figure}[ht] jerojasro@336: \centering jerojasro@336: \grafix{tour-merge-conflict} jerojasro@336: \caption{Conflicting changes to a document} jerojasro@336: \label{fig:tour-merge:conflict} jerojasro@336: \end{figure} jerojasro@336: jerojasro@336: Figure~\ref{fig:tour-merge:conflict} illustrates an instance of two jerojasro@336: conflicting changes to a document. We started with a single version jerojasro@336: of the file; then we made some changes; while someone else made jerojasro@336: different changes to the same text. Our task in resolving the jerojasro@336: conflicting changes is to decide what the file should look like. jerojasro@336: jerojasro@336: Mercurial doesn't have a built-in facility for handling conflicts. jerojasro@336: Instead, it runs an external program called \command{hgmerge}. This jerojasro@336: is a shell script that is bundled with Mercurial; you can change it to jerojasro@336: behave however you please. What it does by default is try to find one jerojasro@336: of several different merging tools that are likely to be installed on jerojasro@336: your system. It first tries a few fully automatic merging tools; if jerojasro@336: these don't succeed (because the resolution process requires human jerojasro@336: guidance) or aren't present, the script tries a few different jerojasro@336: graphical merging tools. jerojasro@336: jerojasro@336: It's also possible to get Mercurial to run another program or script jerojasro@336: instead of \command{hgmerge}, by setting the \envar{HGMERGE} jerojasro@336: environment variable to the name of your preferred program. jerojasro@336: jerojasro@336: \subsection{Using a graphical merge tool} jerojasro@336: jerojasro@336: My preferred graphical merge tool is \command{kdiff3}, which I'll use jerojasro@336: to describe the features that are common to graphical file merging jerojasro@336: tools. You can see a screenshot of \command{kdiff3} in action in jerojasro@336: figure~\ref{fig:tour-merge:kdiff3}. The kind of merge it is jerojasro@336: performing is called a \emph{three-way merge}, because there are three jerojasro@336: different versions of the file of interest to us. The tool thus jerojasro@336: splits the upper portion of the window into three panes: jerojasro@336: \begin{itemize} jerojasro@336: \item At the left is the \emph{base} version of the file, i.e.~the jerojasro@336: most recent version from which the two versions we're trying to jerojasro@336: merge are descended. jerojasro@336: \item In the middle is ``our'' version of the file, with the contents jerojasro@336: that we modified. jerojasro@336: \item On the right is ``their'' version of the file, the one that jerojasro@336: from the changeset that we're trying to merge with. jerojasro@336: \end{itemize} jerojasro@336: In the pane below these is the current \emph{result} of the merge. jerojasro@336: Our task is to replace all of the red text, which indicates unresolved jerojasro@336: conflicts, with some sensible merger of the ``ours'' and ``theirs'' jerojasro@336: versions of the file. jerojasro@336: jerojasro@336: All four of these panes are \emph{locked together}; if we scroll jerojasro@336: vertically or horizontally in any of them, the others are updated to jerojasro@336: display the corresponding sections of their respective files. jerojasro@336: jerojasro@336: \begin{figure}[ht] jerojasro@336: \centering jerojasro@336: \grafix{kdiff3} jerojasro@336: \caption{Using \command{kdiff3} to merge versions of a file} jerojasro@336: \label{fig:tour-merge:kdiff3} jerojasro@336: \end{figure} jerojasro@336: jerojasro@336: For each conflicting portion of the file, we can choose to resolve jerojasro@336: the conflict using some combination of text from the base version, jerojasro@336: ours, or theirs. We can also manually edit the merged file at any jerojasro@336: time, in case we need to make further modifications. jerojasro@336: jerojasro@336: There are \emph{many} file merging tools available, too many to cover jerojasro@336: here. They vary in which platforms they are available for, and in jerojasro@336: their particular strengths and weaknesses. Most are tuned for merging jerojasro@336: files containing plain text, while a few are aimed at specialised file jerojasro@336: formats (generally XML). jerojasro@336: jerojasro@336: \subsection{A worked example} jerojasro@336: jerojasro@336: In this example, we will reproduce the file modification history of jerojasro@336: figure~\ref{fig:tour-merge:conflict} above. Let's begin by creating a jerojasro@336: repository with a base version of our document. jerojasro@336: \interaction{tour-merge-conflict.wife} jerojasro@336: We'll clone the repository and make a change to the file. jerojasro@336: \interaction{tour-merge-conflict.cousin} jerojasro@336: And another clone, to simulate someone else making a change to the jerojasro@336: file. (This hints at the idea that it's not all that unusual to merge jerojasro@336: with yourself when you isolate tasks in separate repositories, and jerojasro@336: indeed to find and resolve conflicts while doing so.) jerojasro@336: \interaction{tour-merge-conflict.son} jerojasro@336: Having created two different versions of the file, we'll set up an jerojasro@336: environment suitable for running our merge. jerojasro@336: \interaction{tour-merge-conflict.pull} jerojasro@336: jerojasro@336: In this example, I won't use Mercurial's normal \command{hgmerge} jerojasro@336: program to do the merge, because it would drop my nice automated jerojasro@336: example-running tool into a graphical user interface. Instead, I'll jerojasro@336: set \envar{HGMERGE} to tell Mercurial to use the non-interactive jerojasro@336: \command{merge} command. This is bundled with many Unix-like systems. jerojasro@336: If you're following this example on your computer, don't bother jerojasro@336: setting \envar{HGMERGE}. jerojasro@336: \interaction{tour-merge-conflict.merge} jerojasro@336: Because \command{merge} can't resolve the conflicting changes, it jerojasro@336: leaves \emph{merge markers} inside the file that has conflicts, jerojasro@336: indicating which lines have conflicts, and whether they came from our jerojasro@336: version of the file or theirs. jerojasro@336: jerojasro@336: Mercurial can tell from the way \command{merge} exits that it wasn't jerojasro@336: able to merge successfully, so it tells us what commands we'll need to jerojasro@336: run if we want to redo the merging operation. This could be useful jerojasro@336: if, for example, we were running a graphical merge tool and quit jerojasro@336: because we were confused or realised we had made a mistake. jerojasro@336: jerojasro@336: If automatic or manual merges fail, there's nothing to prevent us from jerojasro@336: ``fixing up'' the affected files ourselves, and committing the results jerojasro@336: of our merge: jerojasro@336: \interaction{tour-merge-conflict.commit} jerojasro@336: jerojasro@336: \section{Simplifying the pull-merge-commit sequence} jerojasro@336: \label{sec:tour-merge:fetch} jerojasro@336: jerojasro@336: The process of merging changes as outlined above is straightforward, jerojasro@336: but requires running three commands in sequence. jerojasro@336: \begin{codesample2} jerojasro@336: hg pull jerojasro@336: hg merge jerojasro@336: hg commit -m 'Merged remote changes' jerojasro@336: \end{codesample2} jerojasro@336: In the case of the final commit, you also need to enter a commit jerojasro@336: message, which is almost always going to be a piece of uninteresting jerojasro@336: ``boilerplate'' text. jerojasro@336: jerojasro@336: It would be nice to reduce the number of steps needed, if this were jerojasro@336: possible. Indeed, Mercurial is distributed with an extension called jerojasro@336: \hgext{fetch} that does just this. jerojasro@336: jerojasro@336: Mercurial provides a flexible extension mechanism that lets people jerojasro@336: extend its functionality, while keeping the core of Mercurial small jerojasro@336: and easy to deal with. Some extensions add new commands that you can jerojasro@336: use from the command line, while others work ``behind the scenes,'' jerojasro@336: for example adding capabilities to the server. jerojasro@336: jerojasro@336: The \hgext{fetch} extension adds a new command called, not jerojasro@336: surprisingly, \hgcmd{fetch}. This extension acts as a combination of jerojasro@336: \hgcmd{pull}, \hgcmd{update} and \hgcmd{merge}. It begins by pulling jerojasro@336: changes from another repository into the current repository. If it jerojasro@336: finds that the changes added a new head to the repository, it begins a jerojasro@336: merge, then commits the result of the merge with an jerojasro@336: automatically-generated commit message. If no new heads were added, jerojasro@336: it updates the working directory to the new tip changeset. jerojasro@336: jerojasro@336: Enabling the \hgext{fetch} extension is easy. Edit your jerojasro@336: \sfilename{.hgrc}, and either go to the \rcsection{extensions} section jerojasro@336: or create an \rcsection{extensions} section. Then add a line that jerojasro@336: simply reads ``\Verb+fetch +''. jerojasro@336: \begin{codesample2} jerojasro@336: [extensions] jerojasro@336: fetch = jerojasro@336: \end{codesample2} jerojasro@336: (Normally, on the right-hand side of the ``\texttt{=}'' would appear jerojasro@336: the location of the extension, but since the \hgext{fetch} extension jerojasro@336: is in the standard distribution, Mercurial knows where to search for jerojasro@336: it.) jerojasro@336: jerojasro@336: %%% Local Variables: jerojasro@336: %%% mode: latex jerojasro@336: %%% TeX-master: "00book" jerojasro@336: %%% End: