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