web-dev-qa-db-ja.com

チェリーピックが機能した後、gitはどのようにマージしますか?

masterブランチがあると想像してください。

次に、newbranchを作成します

git checkout -b newbranch

newbranchに2つの新しいコミットを作成します。commit1およびcommit2

次に、マスターに切り替えてcherry-pickを作成します

git checkout master
git cherry-pick hash_of_commit1

gitkを調べると、commit1とチェリーピッキングバージョンのハッシュが異なるため、技術的には2つの異なるコミットです。

最後に、newbranchmasterにマージします。

git merge newbranch

異なるハッシュを持つこれらの2つのコミットは問題なくマージされましたが、同じ変更を2回適用する必要があるため、そのうちの1つが失敗することがわかります。

Gitはマージの内容を本当にスマートに分析し、変更を2回適用しないか、これらのコミットが内部でリンクされているとマークされているかを決定しますか?

176
Paul

簡潔な答え

心配しないでください。Gitが処理します。

長い答え

例とは異なりSVN1、Gitはコミットをデルタ形式で保存しませんが、snapshot-basedです2,3。 SVNはマージされた各コミットをパッチとして単純に適用しようとします(そして、説明したとおりの理由で失敗します)が、Gitは通常このシナリオを処理できます。

マージするとき、Gitは両方のHEADコミットのスナップショットを新しいスナップショットに結合しようとします。コードまたはファイルの一部が両方のスナップショットで同一である場合(つまり、コミットが既にチェリーピッキングされているため)、Gitはそれに触れません。

ソース

1 Subversionのスキップデルタ
2 Gitの基本
3 Gitオブジェクトモデル

123
helmbert

このようなマージの後、履歴でチェリーピックされたコミットが2回発生する場合があります。

これを防ぐための解決策は、 article から引用します。これは、重複する(チェリーピックの)コミットを持つブランチに対して、マージ前にリベースを使用することを推奨します。

git cherry-pick後のgit merge:重複したコミットの回避

マスターブランチとブランチbがあるとします:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

今、masterにコミットb1とb3が緊急に必要ですが、bに残っているコミットは必要ありません。したがって、マスターブランチをチェックアウトし、チェリーピックコミットb1およびb3を実行します。

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

結果は次のようになります。

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

マスターで別のコミットをすると、次のようになります:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

ブランチbをマスターにマージする場合:

$ git merge b

次のものが得られます。

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

これは、b1とb3によって導入された変更が履歴に2回現れることを意味します。それを避けるために、マージの代わりにリベースできます:

$ git rebase master b

どちらが得られますか:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

最後に:

$ git checkout master
$ git merge b

私たちに与えます:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

編集デビッドレモンのコメントが想定している修正

35
ephemerr