web-dev-qa-db-ja.com

Mercurialでの後方マージのバックアウト

どのようにして、苦しみを死なせずに、分極した枝のマージの効果を逆転させるのですか

この問題はmonthsに悩まされ、ついに諦めました。

2つの名前付きブランチを持つ1つのリポジトリがあります。 AとB.

Aに発生する変更は必然的にBで発生します。

Bで直接発生する変更は、Aで発生してはなりません。

このような構成では、「B」を「A」にマージすると、Bへのすべての変更がAで行われたかのようにAに表示されるため、リポジトリで深刻な問題が発生します。

この状況から回復する唯一の「通常の」方法は、マージを「バックアウト」することです。つまり、

 hg up -r A 
 hg backout -r BadMergeRev --parent BadMergerevBeforeOnA 

後で正しい方向にマージすることに決め、すべての種類の厄介なことが起こり、特にブランチBで消去またはコメント化されたコードが突然消去されないか、コメントが外れるようになるまで、これはすべて順調に見えます。

これまでのところ、「問題を解決し、すべての問題を手動で修正する」以外に有効な解決策はありません。正直に言うと、それは少し困難です。

これは問題を明確にする画像です:

[元の画像が失われました]

ファイルC&E(または変更C&E)はブランチbにのみ表示され、ブランチaには表示されません。ここのリビジョンA9(ブランチa、revno 9)が問題の始まりです。

リビジョンA10およびA11は、「バックアウトのマージ」および「バックアウトのマージ」フェーズです。

また、リビジョンB12はMercurialであり、削除を意図していない変更を誤って繰り返し削除します。

このジレンマは多くの欲求不満と青い煙を引き起こしており、私はそれに終止符を打ちたいと思います。

注意

フックまたはポリシーのいずれかでリバースマージの発生を禁止しようとするのは明らかな答えかもしれませんが、これを調整する能力はかなり高く、それが発生する可能性は非常に高いため、対策を講じたとしてもmustそれでも必然的にそれがになると仮定しますので、それを解決できるときします。

詳細に

モデルでは、別のファイルを使用しました。これらは問題の音をシンプルにします。これらは単に任意の変更を表しており、別の行になる場合があります。

また、傷害に侮辱を加えるために、ブランチAに大幅な変更があり、「ブランチAの変更は、ブランチBの変更と競合する(変更された(そしてバックアウトされた)変更と競合する)ようになります。代わりにブランチAで

歴史書き換えトリック:

これらすべてのレトロアクティブソリューションの問題は次のとおりです。

  1. 9000件のコミットがあります。
  2. したがって、新たにクローニングするのに30分かかります
  3. リポジトリの1つでも悪いクローンが存在する場合どこかに、それが元のリポジトリと接触して戻ってきて、それを何度も何度も何度も使用する可能性。
  4. 誰もがすでにこのリポジトリのクローンを作成しており、現在、コミットが行われて数日が過ぎています。
  5. そのようなクローンの1つはたまたまライブサイトなので、「その1つをワイプしてゼロから始める」=「大きなノノ」

(私は認めます、上記の多くは少し粗末ですが、それらは私のコントロールの外にあります)。

実行可能な唯一の解決策は、人々がcanおよびwillすべてを間違って行い、この間違いを「取り消す」方法があります。

77
Kent Fredric

私は悪いマージを永久に修正し、手動で差分を確認する必要がないソリューションを見つけたと思います。コツは、歴史を遡り、悪いマージと並行してコミットを生成することです。

したがって、単一の製品の保守バージョンごとに別々のブランチを持つリポジトリーがあります。質問で提起された状況と同様に、以前のバージョンのブランチで行われたすべての変更(つまり、そのバージョンののバグ修正)は、最終的にすべて新しいバージョンのブランチにマージする必要があります。

そのため、具体的には、BRANCH_V8で何かがチェックインされている場合、BRANCH_V9にマージする必要があります。

現在、開発者の1人が次の間違いを犯しています。彼はBRANCH_V9からのすべての変更をBRANCH_V8にマージします(つまり、間違った方向のマージ)。さらに、その悪いマージの後、彼は自分の間違いに気付く前にいくつかの追加のコミットを実行します。

したがって、状況は以下のグラフィカルログに示すとおりです。

o BRANCH_V8-13-不適切なマージの直後の重要なコミット
 | 
 o BRANCH_V8-12-BRANCH_V9からの間違ったマージ
 |\
 | o BRANCH_V8-11-BRANCH_V8にコメントを追加(つまり、最後の既知の良好な状態)
 | | 
 o | BRANCH_V9-10-BRANCH_V9での最後のコミット
 | | 

この間違いは次のように修正できます。

  1. ローカルディレクトリをBRANCH_V8の最後の良好な状態に更新します:hg update 11
  2. その最後の良好な状態の新しい子を作成します:
    1. 一部のファイルを変更$EDITOR some/file.txt(Mercurialは空のコミットを許可しないため、これが必要です)
    2. これらの変更をコミットhg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
      状況は次のようになります:
       o BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成します
       | 
       | o BRANCH_V8-13-不適切なマージの直後の重要なコミット
       | | 
       | o BRANCH_V8-12-BRANCH_V9からの間違ったマージ
       |/| 
       o | BRANCH_V8-11-BRANCH_V8へのコメントの追加
       | | 
       | o BRANCH_V9-10-BRANCH_V9 
      の最後のコミット
  3. 新しく生成されたヘッドを、不適切なマージが発生したリビジョンとマージし、コミットする前にすべての変更を破棄します。 2つのヘッドを単純にマージしないでください。マージ後に発生した重要なコミットが失われるためです

    1. マージ:hg merge 12(競合を無視)
    2. すべての変更を破棄:hg revert -a --no-backup -r 14
    3. 変更をコミットします:hg commit -m "throwing away wrong merge from BRANCH_V9"状況は次のようになります:
       o BRANCH_V8-15-BRANCH_V9から間違ったマージを破棄します
       |\
       | o BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成します
       | | 
       + --- o BRANCH_V8-13-悪いマージの直後の重要なコミット
       | | 
       o | BRANCH_V8-12-BRANCH_V9からの間違ったマージ
       |\| 
       | o BRANCH_V8-11-BRANCH_V8 
      にコメントを追加| | 
       o | BRANCH_V9-10-BRANCH_V9での最後のコミット
       | | 
      

    すなわち。 BRANCH_V8には2つのヘッドがあります。1つは不良マージの修正を含み、もう1つはマージ直後に発生したBRANCH_V8の残りの重要なコミットを含みます。

  4. BRANCH_V8の2つのヘッドをマージします:
    1. マージ:hg merge
    2. コミット:hg commit -m "merged two heads used to revert from bad merge"

最終的にBRANCH_V8の状況は修正され、次のようになります。

 o BRANCH_V8-16-不良なマージから復帰するために使用される2つのヘッドをマージしました
 |\
 | o BRANCH_V8-15-BRANCH_V9から間違ったマージを破棄する
 | |\
 | | o BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成します
 | | | 
 o | | BRANCH_V8-13-不適切なマージの直後の重要なコミット
 |//
o | BRANCH_V8-12-BRANCH_V9からの間違ったマージ
 |\| 
 | o BRANCH_V8-11-BRANCH_V8 
にコメントを追加| | 
 o | BRANCH_V9-10-BRANCH_V9での最後のコミット
 | | 

現在、BRANCH_V8の状況は正しいです。残っている唯一の問題は、BRANCH_V8からBRANCH_V9への次のマージが正しくないことです。これは、BRANCH_V9には不要な不良マージの「修正」でもマージされるためです。ここでの秘訣は、別々の変更でBRANCH_V8からBRANCH_V9にマージすることです:

  • 最初のマージ、BRANCH_V8からBRANCH_V9へ、悪いマージの前からのBRANCH_V8の正しい変更。
  • マージミスとその修正の2番目のマージ。何もチェックする必要なく、すべての変更を破棄します
  • 3番目に、BRANCH_V8からの残りの変更をマージします。

詳細に:

  1. 作業ディレクトリをBRANCH_V9に切り替えます:hg update BRANCH_V9
  2. BRANCH_V8の最後の良好な状態でマージします(つまり、不良マージを修正するために生成したコミット)。このマージは、通常のマージと同様のマージです。競合は通常どおり解決する必要があり、破棄する必要はありません。
    1. マージ:hg merge 14
    2. コミット:hg commit -m "Merging in last good state of BRANCH_V8"現在の状況は:です。
       @ BRANCH_V9-17-BRANCH_V8の最後の良好な状態でのマージ
       |\
       | | o BRANCH_V8-16-不良なマージから復帰するために使用される2つのヘッドをマージしました
       | | |\
       | + --- o BRANCH_V8-15-BRANCH_V9から間違ったマージを破棄する
       | | | | 
       | o | | BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成する
       | | | | 
       | | o | BRANCH_V8-13-不適切なマージの直後の重要なコミット
       | | | /
      +--- o BRANCH_V8-12-BRANCH_V9からの間違ったマージ
       | | /
       | o BRANCH_V8-11-BRANCH_V8 
      にコメントを追加| | 
       o | BRANCH_V9-10-BRANCH_V9での最後のコミット
       | | 
      
  3. BRANCH_V8の悪いマージとその修正をマージし、すべての変更を破棄します:
    1. マージ:hg merge 15
    2. すべての変更を元に戻します:hg revert -a --no-backup -r 17
    3. マージをコミットします:hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" 現在の状況 :
       @ BRANCH_V9-18-BRANCH_V8からの不正なマージとその修正をマージし、すべて破棄します
       |\
       | o BRANCH_V9-17-BRANCH_V8の最後の良好な状態でのマージ
       | |\
       + ----- o BRANCH_V8-16-不良なマージから復帰するために使用される2つのヘッドをマージしました
       | | | | 
       o --- + | BRANCH_V8-15-BRANCH_V9から間違ったマージを破棄する
       | | | | 
       | | o | BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成する
       | | | | 
       + ----- o BRANCH_V8-13-悪いマージの直後の重要なコミット
       | | | 
       o --- + BRANCH_V8-12-BRANCH_V9からの間違ったマージ
       |//
       | o BRANCH_V8-11-BRANCH_V8 
      にコメントを追加| | 
       o | BRANCH_V9-10-BRANCH_V9での最後のコミット
       | | 
      
  4. BRANCH_V8からの残りの変更をマージします:
    1. マージ:hg merge BRANCH_V8
    2. コミット:hg commit -m "merging changes from BRANCH_V8"

最後に、状況は次のようになります。

 @ BRANCH_V9-19-BRANCH_V8からの変更のマージ
 |\
 | o BRANCH_V9-18-BRANCH_V8からの不正なマージとその修正をマージし、すべて破棄します
 | |\
 | | o BRANCH_V9-17-BRANCH_V8の最後の良好な状態でのマージ
 | | |\
 o | | | BRANCH_V8-16-不良なマージから復帰するために使用される2つのヘッドをマージしました
 |\| | | 
 | o --- + BRANCH_V8-15-BRANCH_V9 
から間違ったマージを破棄する| | | | 
 | | | o BRANCH_V8-14-BRANCH_V9からの間違ったマージを修正するためにBRANCH_V8でコミットを生成します
 | | | | 
 o | | | BRANCH_V8-13-不適切なマージの直後の重要なコミット
 |// /
o---+ BRANCH_V8-12-BRANCH_V9からの間違ったマージ
 |//
 | o BRANCH_V8-11-BRANCH_V8 
にコメントを追加| | 
 o | BRANCH_V9-10-BRANCH_V9での最後のコミット
 | | 

手動でdiffを確認する必要がないこれらすべての手順を実行すると、BRANCH_V8とBRANCH_V9が正しくなり、BRANCH_V8からBRANCH_V9への将来のマージも正しくなります。

50
oenli

OK、壊れたリポジトリ(hg init)とは別のディレクトリに新しいemptyリポジトリを作成することから始めます。ここで、最新の既知の適切なバージョンをプルアップし、新しいリポジトリに含めます。 しないでください悪いマージをプルし、-doそれより前にすべてをプルすることを確認してください。古いリポジトリで、Aの最新の既知の適切なバージョンに更新し、これを実行します。

hg graft r1 r2 r3

ここで、r1-3は、不完全なマージ後に行われた変更です。この時点で競合が発生する可能性があります。それらを修正します。

これにより、新しい変更が生成されますAの最新の既知の適切なバージョンに対して。それらの新しい変更を新しいリポジトリにプルします。何も見落とさなかったことを再確認するために、古いリポジトリに対してhg incomingを行います。問題のあるマージとr1-3以外のものが表示された場合は、プルします。

古いリポジトリを捨てます。完了です。マージは新しいリポジトリにはまったく含まれておらず、履歴を書き換える必要はありませんでした。

2
Kevin

ピンチでは、リポジトリを大量の差分にエクスポートし、履歴を編集して、必要なものだけを新しいリポジトリに貼り付けることができるため、損傷のリスクがありません。たぶんあなたの例では悪くないでしょうが、私は本当の歴史がどのように見えるのかわかりません。

より簡単な操作を実行しながら、このページを参照しました。

http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-Mercurial.html

2
Justin Love

Freenodeの#Mercurialで役立つ人々と多くの議論を重ねた後、mpmはpartialソリューションを提供しました。シナリオを複製しようとする偽のリポジトリ)

しかし、私の実際のリポジトリでは、よくわからない理由で、まだ完全ではありません。

この問題を解決するために現在提案されている方法の図を以下に示します。

[元の画像が失われました]

修正すべき問題が今少ないが、差分を比較する必要がある(つまり:b46:b11とb46:b8、a43:a10) vs a43:a9)といくつかの変更を手動で編集します。

リポジトリで動作する保証された方法が得られるまで、この質問を閉じず、答えをとらない。

重要

これを試す人は誰でもリポジトリを複製して、最初にサンドボックスのようにそれを操作する必要があります。 anyマージプロセスで行う必要があるので、それがうまくいかない場合は、それを破棄して、最初からやり直すことができます。

1
Kent Fredric

では、BからAにいくつかのチェンジセットだけをマージしたいですか?すでに苦しんでいるように、あなたがしているようにチェンジセットをバックアウトすることは本当に悪い考えです。

移植拡張機能を使用するか、共通の変更を加えてAとBの両方にマージする3番目のブランチを用意する必要があります。

1
mercurial