このページは Merge の日本語訳です。
そこで、 hg merge を実行すると、 Mercurial が tip での変更点をローカルの変更点へ取り込みます。 tip は作業ディレクトリの2番目の親リビジョンになります。
マージ処理の第1ステップは、チェンジセットの履歴を辿ってマージ予定のバージョン2つの 「共通の祖先」 (rev 1) を探すことです。 この処理はリポジトリ全体でファイルごとに行われます。
マージが完了し、作業ディレクトリ上のマージ結果が正しいと納得できたのであれば、 最後に変更点を commit する必要があります。 これで新しいマージチェンジセット(例の rev 4)が作成され、作業ディレクトリで行ったマージ結果が確定します。
Mercurial ではマージ結果をコミットするまで、次のマージを行うことはできません。 以降のマージで必要となり得る重要な履歴を失う可能性があるためです。
例によって、新しく作成したチェンジセットが作業ディレクトリの親になります。 ここでは元通り、親は1つ(parent 1)になっています。
Branching and merging
Every working directory is potentially a branch and every user effectively works in their own branch. When Mercurial checks out a branch into a working directory, it remembers the changeset that directly led to it so that the next checkin will have the correct parent.
To merge two branches, you pull their heads into the same repository, check out one of them and merge the other, and then check in (commit) the result once you're happy with the merge. The resulting checkin 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 checked-in 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 checkout, Mercurial replaces the working-directory version with the new version. Otherwise it merges the two versions.
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.
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 for checkin.
Merging between repositories
A key feature of Mercurial is its ability to merge between independent repositories in a decentralized manner. 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:
- 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.
- 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.
is not allowed, unless the merged descendant is a named branch. Does anyone know why?