git cherry-pickは、「…38c74dはマージですが、-mオプションが指定されていません」と述べています。


519

私は私のマスターブランチにいくつかの変更を加え、それらをアップストリームにしたいと思っています。次のコミットをチェリーピックすると、gitが言うfd9f578に行き詰まります。

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

gitが私に伝えようとしていることは何ですか?ここでチェリーピックを使用するのは適切ですか?マスターブランチには、上流のブランチで変更されたファイルへの変更が含まれているため、マージの競合が発生することは間違いありませんが、それらを修正しても問題はありません。どの変更がどこで必要かを知っています。

これらは私がアップストリームに持ち込みたいコミットです。

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...

回答:


607

チェリーピックの動作は、チェンジセットが表すdiff(その時点の作業ツリーとその親の作業ツリーの違い)を取得し、それを現在のブランチに適用することです。

したがって、コミットに2つ以上の親がある場合、2つ以上の差分も表します。どちらを適用する必要がありますか?

あなたはfd9f5782人の親との合併だったチェリーピックをしようとしています。したがって、-mオプションを使用して、diffの計算対象となるコマンドをcherry-pickコマンドに通知する必要があります。たとえば、git cherry-pick -m 1 fd9f578親1をベースとして使用します。

私はあなたの特定の状況について確かなことを言うことはできませんが、git merge代わりにを使用するgit cherry-pickことが一般的に推奨されます。マージコミットをチェリーピックすると、指定していない親で行われたすべての変更が-mその1つのコミットに集約されます。あなたは彼らの歴史をすべて失い、彼らのすべての差分を一緒にグロムします。あなたの電話。


3
@wufooあなたもおそらく学ぶべきですgit rebase-それはマージのようなものですが、2つのブランチを統合する代わりに、一方を他方の上に移植して移植します。
Borealid

92
どうやって親番号を知っていますか?
エントロピー

66
@Anentropic 1は「最初の親」、2は「2番目の親」などです。順序は、それらがコミットにリストされている順序です(などで表示されgit showます)。
Borealid 2012年

2
@lkraavあなたはあなたがgit reset --hard HEAD@{1}行方不明のコミットを取り戻すために単にやったかもしれない。git reset歴史の中で「後方」に移動することに限定されていません。git checkout -b mybranch HEAD@{1}も動作します。
Borealid 2013

4
警告:git merge意図しない結果が生じる可能性があります。このコマンドは、親ブランチに存在する他の(古い)コミットをすべて追加します。通常、人々は他のコミットを望まないため、チェリーピックを選択します。必要な変更のみを実装していることを必ず確認してください。
Kay V

52

-m 親番号を意味します。

git docから:

通常、マージのどちら側をメインラインと見なすべきかわからないため、マージをチェリーピックすることはできません。このオプションは、メインラインの親番号(1から開始)を指定し、cherry-pickが指定した親に関連する変更を再生できるようにします。

たとえば、コミットツリーが次のような場合:

- A - D - E - F -   master
   \     /
    B - C           branch one

次にgit cherry-pick E、直面した問題を生成します。

git cherry-pick E -m 1はを使用することを意味しD-Egit cherry-pick E -m 2はを使用することを意味しB-C-Eます。


32

@Borealidの答えは正しいですが、ブランチの正確なマージ履歴を保持する必要はなく、線形化されたバージョンのチェリーピッキングをしたいとします。簡単で安全な方法は次のとおりです。

開始状態:ブランチXにいて、コミットをチェリーピックしたいY..Z

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (オプション) git branch -D tempZ

これは、にtempZ基づいてブランチを作成することですがZY以降の履歴は線形化され、それをX呼び出されたのコピーにチェリーピックしますnewX。(これを変更するよりも、新しいブランチで行う方が安全Xです。)もちろん、ステップ4で競合が発生する可能性があります。これは通常の方法で解決する必要があります(その点でcherry-pick非常によく機能rebaseします)。最後に一時的なtempZブランチを削除します。

ステップ2で「現在のブランチtempZは最新です」というメッセージが表示された場合Y..Zは、すでに線形であったため、そのメッセージを無視してステップ3以降に進んでください。

次に、それが意図newXしたとおりに機能したかどうかを確認してください。

(注:これはシンプルと同じではありません。git rebase Xブランチ上のZそれはとの関係についてどのような方法で依存しないため、XそしてY、共通の祖先の間でコミットがあるかもしれないYあなたはしたくなかったという。)


1
git rebase Y言うCurrent branch tempZ is up to date
バシレフ

それは、それY..Zがすでに線形だったことを意味すると思います。あなたはそのメッセージを無視して、ステップ3と4を進めることができるように
Dairaホップウッド

1
興味深いアイデアですが、私はそれを紙に描いて、何が起こっているのかを十分に理解する必要がありました= D
Chris

2
鮮やかさ。全範囲のgit cherry-pickは、-mオプションが欠落しているか、それが指定されているかのいずれかで不平を言いました。あなたの解決策は黄金でした。(1つの提案:tempZブランチを後で削除)
Otheus

1
これは素晴らしいです!私はチェリーピックに苦労してきましたが、これだけが理にかなっています。選択した文字に少し問題がありました(一部のブランチとコミットは大文字で、一部のブランチは小文字です)
pcarvalho

19

簡素化する。コミットをチェリーピックします。マージをチェリーピックしないでください。

これは、可能なアプローチの利点/リスクを理想的に明確にする、受け入れられた回答の書き直しです。

2つの親とのマージであるfd9f578をチェリーピックしようとしています。

マージをチェリーピックする代わりに、最も簡単なのは、マージの各ブランチから実際に必要なコミットをチェリーピックすることです。

すでにマージしているため、必要なコミットがすべてリストに含まれている可能性があります。それらを直接チェリーピックします。マージコミットをいじる必要はありません。

説明

チェリーピックの動作は、チェンジセットが表す差分(その時点の作業ツリーとその親の作業ツリーの違い)を取得し、変更セットを現在のブランチに適用することです。

マージの場合のように、コミットに2つ以上の親がある場合、そのコミットも2つ以上の差分を表します。エラーは、どのdiffが適用されるかが不確実であるために発生します。

代替案

マージと関連するコミットのチェリーピックを含める必要があると判断した場合、2つのオプションがあります。

  1. (より複雑であいまいで、履歴も破棄されます)どの親を適用するかを指定できます。

    • -mそのためには、オプションを使用します。たとえばgit cherry-pick -m 1 fd9f578、マージにリストされている最初の親をベースとして使用します。

    • また、マージコミットを選択すると、指定していない親で行われたすべての変更が-mその1つのコミットに集約されることも考慮してください。あなたは彼らの歴史をすべて失い、彼らのすべての差分を一緒にグロムします。あなたの電話。

  2. (よりシンプルで使い慣れた、履歴を保持)のgit merge代わりに使用できますgit cherry-pick

    • の通常のようにgit merge、マージするブランチに存在するすべてのコミットを適用しようとし、それらをgitログに個別にリストします。

2

単一のコミットを選択するのに適した@Daira Hopwoodメソッドの簡略化。一時的なブランチは必要ありません。

著者の場合:

  • Zはコミットが必要です(fd9f578)
  • Yはその前にコミットします
  • X現在の作業ブランチ

次に行います:

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

2
もちろん、これは元のコミットに関連付けられたメタデータを失います。それがもっと簡単かどうかは意見の問題だと思います。メタデータを失い、コード全体の変更のみを保持したい場合に、これを使用することがあります。YがZの直接の親でなくても機能することに注意してください(その場合、変更は押しつぶされます)。
Daira Hopwood、2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.