{X} This page is proposed for deletion. See our wiki cleanup plan for more information.

Merge

hg merge

A merge combines two separate changesets in a repository into a merge changeset that describes how they combine. Merging is the process of joining points on two branches into one, usually at their current heads.

The merge process is simple. Usually you will want to merge the tip into your working directory.

Thus you run hg merge and Mercurial will incorporate the changes from the tip into your local changes; Tip will then become the second parent revision of your working directory.

The first step of this process is tracing back through the history of changesets and finding the 'common ancestor' of the two versions that are being merged (rev 1). This is done on a repository-wide and a file-by-file basis.

For files that have been changed in both changesets, a three-way merge is attempted using a merge program to add the changes made remotely into the changes made locally. If there are conflicts between these changes, the user is usually prompted to interactively resolve them.

After you've completed the merge and you're satisfied that the results are correct in your working directory state, you still need to commit your changes. This creates a new merge changeset (rev 4 in the example), freezing the result of the merge you had prepared in the working directory.

Mercurial won't allow you to perform another merge until you've done this commit as that would lose important history that will be needed for future merges.

As usual, the newly created changeset becomes the new parent of the working directory, which now again has just a single parent (parent 1).

Help text: http://www.selenic.com/mercurial/hg.1.html#merge

See also: TutorialMerge, MergeMultipleHeads

Technical Details

Branching and merging

Every working directory is potentially a branch and every user effectively works in their own branch. When Mercurial updates to a branch into a working directory, it remembers the changeset that directly led to it so that the next changeset will have the correct parent.

To merge two branches, you pull their heads into the same repository, update to one of them and merge the other, and then commit the result once you're happy with the merge. The resulting changeset has two parents.

Mercurial decides when a merge is necessary by first determining whether the working directory contains uncommitted changes. This determination effectively turns the working directory into a branch of the committed version on which it is based. If the working directory is a direct ancestor or descendant of the second version that we're attempting to update to, Mercurial replaces the working-directory version with the new version. Otherwise it merges the two versions.

Graph merging

Merging a pair of directed acyclic graphs (DAGs) -- the family tree of the file history -- requires determining whether nodes in different graphs correspond. Comparing the node contents (or hashes of the contents) is incorrect because it ignores the history.

However, using the nodeid avoids this error because the nodeid describes the file's contents and its graph position relative to the root. A merge simply checks whether each nodeid in graph A is in graph B and vice versa (for example using a hash table), and Mercurial adds the new nodes to the append-only revlog.

Merging manifests

To merge manifests, first compare them and decide which files need to be added, deleted, and merged.

For each file to be merged, perform a graph merge and resolve conflicts as above. It's important to merge files using per-file DAGs rather than just changeset-level DAGs as this diagram illustrates:

 M   M1   M2

   AB
    |`-------v     M2 clones M (mainline)
   aB       AB     file A is change in mainline
    |`---v  AB'    file B is changed in M2
    |   aB / |     M1 clones M
    |   ab/  |     M1 changes B
    |   ab'  |     M1 merges from M2, changes to B conflict
    |    |  A'B'   M2 changes A
     `---+--.|
         |  a'B'   M2 merges from mainline, changes to A conflict
         `--.|
            ???    depending on which ancestor we choose, we will
                   have to redo A hand-merge, B hand-merge, or both
                   but if we look at the files independently, the
                   merge is easy

The result is a merged version in the working directory, waiting to be committed.

Merging between repositories

A key feature of Mercurial is its ability to merge between independent repositories in a decentralized fashion. Each repository can act as a read-only server or as a client. A client pulls from the server all branches that it has not seen and adds them to its graph. This pull is done in two steps:

  1. Searching for new roots.
    • This part begins by finding all new heads and searching backwards from those heads to the first unknown nodes in their respective branches. These nodes are the roots used to calculate the changegroup: the set of all changesets starting at those roots. Mercurial takes pains to make this search efficient in both bandwidth and round-trips.

  2. Pulling a changegroup.
    • Once the roots are found, the changegroup can be transferred as a single streaming transfer. This transfer is organized as an ordered set of deltas for changesets, manifests, and files. Large chunks of deltas can be directly added to the repository without unpacking so the pull is quick.

(See WireProtocol for more details.)

Once the remote changes have been pulled into the current repository, merging proceeds as described above.

Notes


CategoryCommand

Fran├žais

Merge (last edited 2012-11-11 12:50:30 by abuehl)