2017-03-03 23 views
1

以下のようなコミットグラフがあります。 *とマークされたコミットは、多くのコミットを表します。すでにマージされたブランチを再マージするには?

A* 
    | 
    B--------- 
    |  | 
    C*  D* <- old feature branch 
    |  | 
    E--------- 
    | 
    F* 
    | 
    G  <- master 

マージコミットEが正しく行われず、C *の一部の変更(すべてではない)が失われました。このマージをやり直して、現在のマスターに変更を再導入するにはどうすればよいですか?

すべてがすでにプッシュされています(オープンソースプロジェクト)ので、履歴の変更はオプションではありません。

私はコミットのC *からパッチを作成しようとしたマスターにそれを適用されますが、C *からの変更の一部が正しくマージされているので、それがコミットするので、プロジェクトが進化しているため、約80%パッチは失敗します。

理想的には、C *のすべての変更を適用し、それらを適用してすべての競合を解決します。しかし、ブランチはすでにマージされているので、gitは変更を検出せず、再度マージすることもできません。

$ git checkout 5bc5295 # C 
HEAD is now at 5bc5295... cleanup 

$ git checkout -b "missing-commits" 
Switched to a new branch 'missing-commits' 

$ git checkout master 
Switched to branch 'master' 
Your branch is up-to-date with 'origin/master'. 

$ git merge missing-commits 
Already up-to-date. 
+0

をあなたはgitのは、間違ったコミットを元に戻してみました。これにより、悪いコミットによってもたらされた変更や失われた変更が取り消されます。何かが戻ってきます。 –

+0

@Eyortherどのように役立つでしょう、マージは間違ったコミットですか? – Vampire

答えて

1

理想的には、C *のすべての変更を適用して、それらを適用してすべての競合を解決します。

いいえ、理想的にあなたが時間を巻き戻しますが、それは(が、正しくこの時間)当時あったようにマージを行う、そしてF*変更を再適用し、正しいmasterで終わります。

あなたはこのようにそれを行うことができます:あなたはリベース中にすべての競合を処理するために管理する場合

git checkout missing-commits 
git checkout -b correct-merge 
git merge D # do it right, this time around! 
git checkout master 
git checkout -b correct-master 
git rebase --onto correct-merge wrong-merge correct-master # have fun with the mother of all rebases! 

を、あなたは枝correct-masterで、もともとは、あなたが望んでいた正確に何で終わるだろう。

あなたは歴史を変更したくないので、あなたはその後、大きなパッチを作成することができますし、あなたの現在のmasterにそれを適用しますが、私は、このアプローチは、より多くの(あなたの作業ディレクトリyourreposにすべての仕事をしたと仮定して)好き:

cd yourrepos ; git checkout correct-master ; cd .. 
cp -a yourrepos newrepos 
rm -rf newrepos/.git 
cd yourrepos ; git checkout master ; cd .. 
cp -a yourrepos/.git newrepos/ 

、あなたがnewreposを入力してgit statusを行うとき、あなたは枝masterになり、パッチを適用したかのように、mastercorrect-masterの間で正確にすべての変更が表示されます。削除されたファイル、新しいファイル、変更されたファイル、変更されたアクセス許可、変更されたシンボリックリンクなどをキャッチします。

理想的には、すべてが正しく行われた場合、正確には、失われたコミットをCから正確に表示します。 git addのお気に入りのバリアントを使用し、最終的にはgit commit(または複数の場合もあります)を使用すると、完了です。履歴は書き換えられていません。

+0

rebaseコマンドの必要性を理解していません。いったん私は正しいマージブランチを持っていれば、それをマスターにマージできませんでしたか?それはリベースを使うこととどう違うでしょうか? –

+0

@ JohnM、それは動作するか動作しない可能性がありますが、意味的には正しいことではありません。マージ操作は、共通の祖先から分岐した2つのものを一緒にするために行われます。これはあなたがここでやっていることではありません。 Rebaseではなく、ツリー上の別の場所で一連のコミットを移植するようになっています。これは、ここでやっていることです。実用的な利点は、rebaseはコミットによってコミットするので、不運な場合でも簡単に競合を解決できる可能性が高く、ほとんどのコミットで同じ競合が発生すると、それは深刻になる可能性があります。あなたは両方のコースを試すことができます! – AnoE

+0

ありがとう、私はそれをrebaseすることができました。私がやらなければならなかった小さな変更の1つは、間違ったマージの後でrebaseすることでした。コミットされていないコミットは 'git rebase -onto correct-merge wrong-merge correct-master'です。しかし、私は最終的にこれがどのように機能し、それはかなりきちんと理解しています。 –

0

は無地のパッチを作成し、git format-patchgit amを使用するためにそれらを適用するのではなく、試してみてください。これにより、アプリケーションがただ失敗するgit applyとは異なり、マージツールを使用して競合を解決できる通常の競合状態が発生します。

+0

'git format-patch'や' git show'で生成されたパッチを 'git apply -3'して、マージ機構を呼び出すことができます。 ( 'git am'は' git apply -3'を内部的に使用しています) – torek

0

あなたはチェリーピックで試すことができます:コミットが祖先であるため、

git checkout master 
git cherry-pick B..[last_commit_of_C*] 

Gitはチェリーピックを確認するように依頼することがあります。

0

Gitはスナップショットを保存してその場で変更を検出するので、悪いコミットと良いものの違いを処理する方法は、子孫として何かと同じように悪いものを記録することですそれを考えてください。正しい家系gitの言うことgit reset --softを使用します。

git checkout badmerge^1 # generate the right result 
git merge badmerge^2 

git reset --soft badmerge # as an improvement on the wrong result 
git commit 

git checkout master  # merge the difference now that git sees it 
git merge @{1} -m "applying corrections to a bad merge" 
関連する問題