15

これは説明が難しい状況ですので、ご容赦ください。デフォルトdevの 2 つのメインブランチを持つ Mercurial リポジトリがあります。

通常、作業はdevの名前付きブランチ(機能ブランチ) で行われます。一度に多数のフィーチャー ブランチが存在する場合があります。そのブランチで作業が完了すると、devにマージされます。

リリースを準備するときが来ると、別の名前付きブランチがdevから作成されます(リリース ブランチ)。リリースから機能全体を除外する必要がある場合があります。その場合、feature ブランチがdevにマージされた場所からのマージ変更セットは、新しいリリース ブランチから取り消されます。

リリース ブランチをリリースする準備が整うと、デフォルトにマージされます(したがって、デフォルトは常に本番環境でのコードの状態を表します)。作業は、devブランチと機能ブランチで通常どおり続行されます。

この問題は、以前のリリースで取り消された機能を含め、別のリリースを行うときに発生します。新しいリリース ブランチが通常どおり ( devから) 作成されます。この新しいリリース ブランチには、以前のリリース ブランチからバックアウトされた機能が含まれるようになりました (リリース ブランチでバックアウトが実行され、マージ変更セットがdevブランチに残っているため)。

今度は、リリース ブランチがリリースの準備ができて default にマージされるとき、以前のリリース ブランチでのマージ バックアウトの結果としてバックアウトされた変更は、 defaultマージされません。これはなぜですか?新しいリリース ブランチにはフィーチャー ブランチの変更セットがすべて含まれているため (何もバックアウトされていません)、なぜデフォルトブランチもこれらの変更セットのすべてを受け取らないのでしょうか?

上記のすべてを理解するのが難しい場合は、基本的な問題を示す TortoiseHg のスクリーンショットをご覧ください。「branch1」と「branch2」はフィーチャー ブランチ、「release」と「release2」はリリース ブランチです。

ここに画像の説明を入力

4

2 に答える 2

26

問題は、マージの動作があなたが思っているものとは異なることだと思います。あなたが書く

新しいリリースブランチにはすべての機能ブランチチェンジセットが含まれているため(バックアウトされていないものはありません)、デフォルトブランチがこれらのチェンジセットのすべてを受け取らないのはなぜですか?

2つのブランチをマージする場合、あるブランチから別のブランチにすべての変更を適用すると考えるのは誤りです。したがって、defaultブランチはから変更セットを「受信」しませんrelease2。これが私たちが通常マージについて考える方法であることを私は知っていますが、それは不正確です。

2つのチェンジセットをマージすると、実際に何が起こるかは次のとおりです。

  1. Mercurialは、2つのチェンジセットの共通の祖先を見つけます。

  2. Mercurialは、2つのチェンジセット間で異なるファイルごとに、祖先ファイル、最初のチェンジセット内のファイル、および2番目のチェンジセット内のファイルを使用して3方向マージアルゴリズムを実行します。

あなたの場合、リビジョン11と12をマージしています。最も一般的でない祖先はリビジョン8です。これは、Mercurialがそこのリビジョンのファイル間で3方向のマージを実行することを意味します。

  • リビジョン8:バックアウトなし

  • リビジョン11:機能ブランチがバックアウトされました

  • リビジョン12:バックアウトなし

3者間マージでは、変更は常に変更よりも優先されます。Mercurialは、ファイルが8から11の間で変更されていることを確認し、8から12の間で変更がないことを確認します。したがって、マージではリビジョン11から変更されたバージョンを使用します。これは、すべての3方向マージアルゴリズムに適用されます。完全なマージテーブルは次のようになります。ここoldnew、、、...は3つのファイル内の一致するハンクのコンテンツです。

ancestor  local  other -> merge
old       old    old      old (nobody changed the hunk)
old       old    new      new (they changed the hunk)
old       new    old      new (you changed the hunk)
old       new    new      new (hunk was cherry picked onto both branches)
old       foo    bar      <!> (conflict, both changed hunk but differently)

この驚くべきマージ動作のために、マージチェンジセットをバックアウトするべきではないのではないかと心配しています。Mercurial 2.0以降では、マージをバックアウトしようとすると中止され、文句が表示されます。

一般に、3方向マージアルゴリズムは、すべての変更が適切であると想定していると言えます。したがって、マージbranch1してdevから、後でバックアウトを使用してマージを元に戻すと、マージアルゴリズムは、状態が以前よりも「良好」であると見なします。これは、バックアウトされた変更を元に戻すために、後で再マージすることはできないことを意味しますbranch1dev

にマージするときに「ダミーマージ」を使用することができますdefault。マージするだけで、マージ先のリリースブランチからの変更を常に保持しますdefault

$ hg update default
$ hg merge release2 --tool internal:other -y
$ hg revert --all --rev release2
$ hg commit -m "Release 2 is the new default"

それは問題を回避し、力defaultはのようになりrelease2ます。defaultこれは、リリースブランチにマージされない限り、変更がまったく行われないことを前提としています。

スキップされた機能を使用してリリースを作成できる必要がある場合、「正しい」方法は、それらの機能をまったくマージしないことです。マージは強力なコミットメントです。マージチェンジセットには、両方の祖先からのすべての優れた機能が含まれていることをMercurialに伝えます。Mercurialがマージ時に独自のベースリビジョンを選択できない限り、3方向マージアルゴリズムではバックアウトについての考えを変えることはできません。

ただし、できることは、バックアウトをバックアウトすることです。これは、機能ブランチからリリースブランチに変更を再導入することを意味します。だからあなたは次のようなグラフから始めます

release: ... o --- o --- m1 --- m2
                        /      /
feature-A:   ... o --- o      /
                             /
feature-B:  ... o --- o --- o 

ここで、A機能が不良であると判断し、マージを取り消します。

release: ... o --- o --- m1 --- m2 --- b1
                        /      /
feature-A:   ... o --- o      /
                             /
feature-B:  ... o --- o --- o 

次に、別の機能をリリースブランチにマージします。

release: ... o --- o --- m1 --- m2 --- b1 --- m3
                        /      /             /
feature-A:   ... o --- o      /             /
                             /             /
feature-B:  ... o --- o --- o             /
                                         /
feature-C:  ... o --- o --- o --- o --- o 

A機能を再導入したい場合は、バックアウトできますb1

release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
                        /      /             /
feature-A:   ... o --- o      /             /
                             /             /
feature-B:  ... o --- o --- o             /
                                         /
feature-C:  ... o --- o --- o --- o --- o 

デルタをグラフに追加して、何がいつどこで変化するかをより適切に示すことができます。

                     +A     +B     -A     +C     --A
release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2

この2回目のバックアウトの後、feature-A新しいチェンジセットが追加された場合に備えて、再度マージできます。マージするグラフは次のようになります。

release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
                        /      /             /
feature-A:   ... o -- a1 - a2 /             /
                             /             /
feature-B:  ... o --- o --- o             /
                                         /
feature-C:  ... o --- o --- o --- o --- o 

そして、あなたはマージa2b2ます。共通の祖先はになりますa1。つまり、3者間マージで考慮する必要がある変更は、a1anda2a1andの間の変更だけですb2。ここb2にはすでに変更の大部分が「含まれている」a2ので、マージは小さくなります。

于 2012-02-29T14:20:24.317 に答える
0

マーティンの答えは、いつものようにお金にかかっていますが、私は 2p を追加したかっただけです。

これについての別の考え方は、バックアウトは何も削除せず、逆の変更を追加するというものです。

したがって、マージするときは、次のことをしていません。

Branch after changes <-> Branch before changes => Result with changes

あなたはやっている:

Branch after changes <-> Branch after changes with removal of changes => Result with changes removed.

基本的に、最初のリリースはうまくいきませんでした。すべてを含めて機能を厳選するよりも、リリースに機能を厳選する方がよいでしょう。グラフトはここで役立つかもしれませんが、すべての落とし穴を知るために怒りでそれを使用しようとしたことはまだありません.

于 2012-02-29T17:54:49.870 に答える