「スカッシュ マージ」はまったくマージではないため、この図はいくつかの重要な点で間違っています。
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 はコミットD、E、F、I、J、および(行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 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、 、C、G、H、L、 、M、N、O. から始まるリベースOは、すべての作業が完了したソース ツリーから始まります。