1

わかりましたので、一連のコミットを押しつぶすことで少し問題が発生しました。これから回復する方法があるかどうかを知りたいです。これが何が起こったのかです。

出発点は次のとおりです。

  D (mybranch)
 /
A--B--C (master)

両方のブランチで作業が行われました。

  D--E--F (mybranch)
 /
A--B--C--G--H (master)

masterからへの変更をマージしましたmybranch(残念ながらここで押しつぶされたため、B、C、G、および H は単一のコミット H' on に結合されましたmybranch):

  D--E--F--H' (mybranch)
 /         \   
A--B--C--G--H--L--M (master)

両方のブランチで作業が行われました。

  D--E--F--H'--I--J--K (mybranch)
 /         \   
A--B--C--G--H--L--M--N--O (master)

mybranchそして今、からの変更を元にマージしたいのですmasterが、同じファイルが両方によって変更されたという大量の競合が発生しています。

mybranchからへのクリーンなマージを行うために今できることについて何か提案はありmasterますか?

更新 1

ここに出力がありますgit log

>git log --pretty=raw -n 1 d25ae411 (this is H')
commit d25ae411ffff9c59570437b50bfb89df7720af90
tree 3ffbb07a722fe70a66c64b257bb4a8c81235a027
parent aed6b526524db5c05bdb2518db18cf5ecfd8ef9d

>git log --pretty=raw -n 1 69c01f42 (this is H)
commit 69c01f42e73dad9f504c084de58b6a57f0d8506d
tree 323d506718f99d523fdd9529d8b6114a01657025
parent 7065134c416f7ecc6cf66c30ea5e019c625c9c19
parent 8170ca5ce1ce46df6b9f04d80cfad63b6f082b66
4

2 に答える 2

1

「スカッシュ マージ」はまったくマージではないため、この図はいくつかの重要な点で間違っています。

  D--E--F--H'--I--J--K (mybranch)
 /         \
A--B--C--G--H--L--M--N--O (master)

...しかし幸いなことに、これをできるだけ簡単に処理する方法を知るために、私たちが知る必要があるすべてのことを教えてくれます。

最初に、それはmasterからH'のスカッシュ マージだと言いました。おそらくそうあるべきでした(「後の」コミットを「以前の」コミットの右側に配置する必要があります) が、実際にはマージをまったく示すべきではなく、おそらく別の名前にする必要があります。 mybranch\/

したがって、グラフの断片を再描画する方法は次のとおりです (とにかく、私が管理できる限り正しく - これを使用する前に、これらすべてを慎重に再確認することをお勧めします)。

  D--E--F----BCGH'--I--J--K   <-- mybranch
 /
A--B--C--G--H----L--M--N--O   <-- master

ここで名前が付けられたコミットBCGH'は、コミットのスカッシュ「マージ」1でありB--C--G--H、これは と呼ばれていましたH'。これは、元の 4 つのコミットからのすべての作業のコピーです。

リベースを使用し、スカッシュを省略

mybranchの先端にリベースすることをお勧めしmasterます。これはおそらく最も簡単で最良の方法ですが、「履歴を書き換える」( commit 後に作業を開始したふりをするO) ことを意味します。これを行うには、インタラクティブなリベースを使用します。

$ git checkout mybranch
$ git rebase -i master

BCGH'次に、具体的にリストからコミットを削除しpickます。これにより、Git はコミットDEFIJ、および(行Kの順序を変更しない限り、この順序で) のそれぞれをチェリー ピックするように要求されます。pick

  D--E--F----BCGH'--I--J--K   [will be abandoned]
 /
A--B--C--G--H----L--M--N--O   <-- master
                           \
                            D'-E'-F'-I'-J'-K'   <-- mybranch

マージを使用して、Git に作業を行わせる

または、本当にマージしたい場合は、 commit から始まる新しい(ただし一時的な) ブランチを作成し、A同じ 6 つのコミットだけを選択します。

$ git checkout -b tempbranch mybranch~7  # this should start from A
$ git cherry-pick mybranch~7..mybranch~4 # pick D, E, and F
$ git cherry-pick mybranch~3..mybranch   # pick I, J, and K

  D--E--F----BCGH'--I--J--K   <-- mybranch
 /
A--B--C--G--H----L--M--N--O   <-- master
 \
  D'--E'--F'--I'--J'--K'      <-- tempbranch

からのコミットのコピーtempbranchがないことに注意してください。それ以外は、マスターの先端にリベースした場合に得られるものと基本的に同じです。2 この特定のコピーを作成するポイントは、この新しい commit に関連付けられたソース ツリーを取得することです。BCGH'masterK'

$ git merge master

新しい (一時的ではありますが) マージ コミットTを作成するにはBCGH':

  D--E--F----BCGH'--I--J--K   <-- mybranch
 /
A--B--C--G--H----L--M--N--O   <-- master
 \                         \
  D'--E'--F'--I'--J'--K'----T   <-- tempbranch

この新しいマージ コミットTには、からへの実際のマージを行う場合に取得したいソース ツリーがあります。それでは、 commit が原因でマージの競合で失敗するマージを開始しましょう。mastermybranchBCGH'

$ git checkout mybranch
$ git merge master

これは競合で失敗するため、マージ結果全体を破棄し、それを一時的なマージのツリーに置き換えることで、すべての競合を解決しましょうT.すべてを参照するため、ここでは git ツリーの最上位にいる必要があることに注意してください。

$ git rm -rf .
$ git checkout tempbranch -- .

最初のステップでは、作業ツリー全体 (およびインデックス/ステージング領域の内容) を破棄し、2 番目のステップでは、 commit である の一番端のコミットからまったく新しい作業ツリー (およびインデックスの内容) を作成しtempbranchますT

これで結果をコミットできます (ただし、最初に注意深くチェックするのが賢明ですが、もちろん、tempbranchここまで到達する前にブランチでそれを行うこともできます)。コミットすると、次のようになります。

  D--E--F----BCGH'--I--J--K-P   <-- mybranch
 /                         /
A--B--C--G--H----L--M--N--O     <-- master
 \                         \
  D'--E'--F'--I'--J'--K'----T   <-- tempbranch

からのソース ツリーを使用しPた適切なマージTです。tempbranch完全に削除しても安全です。

$ git branch -D tempbranch

commit を省略した一時的なブランチを使用して Git が行ったマージが残っていますBCGH'

より多くのオプションと、何をするにしてもその方法と理由に関するメモ

commit から始まる新しいブランチを作成し、(スカッシュの「マージ」の代わりに)Fからこの新しいブランチへの実際のマージを実行し、次に からチェリー ピックして別の実際のマージを実行するなど、これを行う追加の方法があります。masterIKmaster

他の方法と比較して、いずれかの方法を使用する唯一の正当な理由は次のとおりです。

  • その方法が好きなら;
  • それがあなたにとってより簡単であれば; および/または
  • 他の人がそれらのコミットのいくつかを持っていて、他の人にもっと仕事をさせたくない場合。

最後に、コミットは 2 つのことを提供します:状態(作業ツリー、コミット作成者、日付、ログ メッセージなどのメタデータ) と履歴(このコミットの前にどのようなコミットがあったか)。アイデアは、必要な数だけコミットを行い、意味を理解して協同開発を可能にするのに十分な状態と履歴を提供することです。あまり多くの状態と履歴を提供して、意味を曖昧にして協同開発を無効にすることはありません。


1「マージ」を引用符で囲んでいるのは、スカッシュ マージがマージではないためです。マージは 2 つ以上の親を持つコミットであり、これらのスカッシュ「マージ」コミットは 2 番目の親を記録しません: 重要な情報を破棄します。

2ここで言いたいのは、コミットに関しては、リベースする場合に必要なものと同じだということです。、、 、 、 、 B 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、CGHL、 、MNO. から始まるリベースOは、すべての作業が完了したソース ツリーから始まります。

于 2016-05-02T19:14:43.557 に答える
0

どういうわけか、歴史はあなたが思っているものではなく、からmasterへの変更のマージmybranchがどういうわけか適切に行われていなかったのではないかと思います.

その最初のマージは、多くの競合と修正で苦労しましたか? そうじゃないなら捨てて最初からやり直せばいいのに

git checkout -b mybranch_test F
git rebase --onto F H' mybranch_test

待つ必要はありません。コミットをgit checkout myrbanch; git rebase --interactive F実行して削除するだけです。H'

これは非常に簡単にテストできるはずです。git を使用すると、このようなことを無料で試すことができるので、試してみてください。

H'これはすべて、マージが競合を引き起こす大きな変更を導入しなかったという前提に基づいていますが、これは真実である場合とそうでない場合があります。

于 2016-05-02T15:28:20.287 に答える