2012-02-29 10 views
15

これは説明するのが難しい状況なので、私に同行してください。私は2つの主要なブランチ、デフォルトdevを持つMercurialリポジトリを持っています。あるブランチのMercurialバックアウトが他のブランチに影響するのはなぜですか?

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

リリースを準備するときに、別の名前のブランチがdev(リリースブランチ)から作成されます。場合によっては、フィーチャー全体をリリースから除外する必要があります。その場合、機能ブランチがマージされたマージ変更セットdevは、新しいリリースブランチからバックアウトされます。

リリースブランチをリリースする準備ができていると、それはデフォルト(そうデフォルトは常に生産のコードの状態を表している)にマージされます。 デベロッパーブランチとフィーチャーブランチで正常に処理が続行されます。

この問題は、以前のリリースでバックアウトされていた機能を含む別のリリースを行うときに発生します。新しいリリースブランチが通常どおりに作成されます(off of dev)。この新しいリリースブランチには、以前のリリースブランチからバックアウトされた機能が含まれています(バックアウトはリリースブランチで実行され、マージチェンジセットはdevブランチに残ります)。リリースブランチはリリースの準備ができているとデフォルトにマージされ

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

上記のすべてが難しい場合は、基本的な問題を示すTortoiseHgのスクリーンショットを示します。 「支社」と「BRANCH2」機能ブランチあり、「解放」と「リリース2」はリリースブランチです:

enter image description here

+0

hg diff -r 9 -r 12 ??? –

答えて

25

私はこの問題は、マージはあなたが思うよりも異なる動作をすることであると信じています。あなたは書きます

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

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

  1. Mercurialは2つのチェンジのための共通の祖先を見つける:あなたは2つのチェンジをマージするとき、本当に何が起こる

    は次のとおりです。

  2. 2つのチェンジセットで異なるファイルごとに、Mercurialは先祖ファイル、最初のチェンジセットのファイルと2番目のチェンジセットのファイルを使用してthree-way merge algorithmを実行します。あなたのケースでは

、リビジョン11と12をマージしている以上の共通の祖先が改訂8です。これは、Mercurialは、三方があるリビジョンからファイル間でマージを実行することを意味します:

  • リビジョン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) 

私は怖いもので、すべての理由は、この驚くべきマージ動作のmerge changeset shouldn't be backed out。 Mercurial 2.0以降では、マージを取り消そうとすると中止して文句を言うでしょう。

一般に、3ウェイマージアルゴリズムでは、がすべて変更されているとみなすことができます。。したがって、branch1devにマージし、後でバックアウトでマージを元に戻すと、マージアルゴリズムは状態が以前よりも優れているとみなします。つまり、後でbranch1devに再度マージして、バックアウトされた変更を元に戻すことはできません。

defaultにマージするときに「ダミーマージ」を使用することができます。あなたは、単にマージし、常にdefaultにあなたがマージしているリリースブランチから変更を保つ:ちょうどrelease2ようになり、問題と力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に全く変更が加えられていないことを前提としています。

スキップされた機能を備えたリリースを作成できる必要がある場合、「正しい」方法は、それらの機能をまったくマージしないことです。マージは強力なコミットメントです:あなたはMercurialに、マージチェンジセットは両方の祖先からのすべての良いものを持っていると伝えます。 Mercurialがあなたにpick your own base revision when mergingを渡さない限り、三方向マージアルゴリズムはあなたがバックアウトについてあなたの心を変えることを許さないでしょう。

ただし、できることは、バックアウトのバックアウトです。これは、フィーチャーブランチからリリースブランチに変更を再導入することを意味します。

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 
だからあなたはあなたが今機能が悪かったと判断し、マージをバックアウト

release: ... o --- o --- m1 --- m2 
         / /
feature-A: ... o --- o /
          /
feature-B: ... 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 

をこの第二のバックアウトした後、あなたは新しいチェンジセットが追加されている場合には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方向マージで考慮する必要がある変更は、a1a2a1b2の間の変更だけです。ここではb2にはすでに "in"の変更内容が含まれていますa2したがって、マージは小さくなります。

+0

もう一つの考え方は、あなたが何か(最後の共通の祖先を分岐の前に)のコピーをとり、それらのコピーを2人の異なる人に与えたことです。今では、その人の一人がコピーに何かをします。後で2つのコピーを1つに戻したいときは、「彼は自分のコピーに何かしました」と「他の人は何もしませんでした」、Mercurial 1つの支店で行われた変更を喜んで受け入れ、それが何であるかにかかわらず適用します。 –

+0

マーティン - 優秀な説明は、石で学び、打つ。あなたが残念なことにどのようなアドバイスをしているのですか?**スキップされた機能を使ってリリース**を行う必要があります(バックアウトが悪い場合は、私たちが見ています) –

+0

@LazyBadger:私はこれを処理するためのアドバイスをいくつか与えようとしました。 –

0

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

これについてもう1つ考えてみると、バックアウトでは何も削除されず、逆の変更が加えられます。

だからあなたはあなたがやっていないマージする場合:

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

あなたがやっている:

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

は、基本的に最初のリリースがひどく行われました。すべての機能とチェリーピック機能を含めるよりも、リリースに機能をチェリーピックする方が良いでしょう。 Graftがあなたを助けてくれるかもしれませんが、私はまだ怒りでそれを使って、すべての落とし穴を知っているわけではありません。

+1

"すべてのものとチェリーピックの機能を含むよりも、リリースに機能をチェリーピックする方が良いでしょう - 実際の生活では合理的な長いリリースサイクルではほとんど不可能 –

+0

与えられました - あなたはチェリーピックに行くつもりはありませんすべてのチェンジセット。それは、狂気になるという確かな火の方法でしょう。ブランチポイントを慎重に選択し、不要な機能をリリースに入れないでください。チェリーはそれ以降に選ぶ。 –

+0

私のリリースに10-20の機能があり、同量のバグ修正(デフォルトではmergeset) - 実数です - チェリーピッキングはロシアンルーレットになります –

関連する問題