Gitにはgit cherry-pick
というコマンドがあります。英語のcherry pickとは自分の気に入ったものだけをつまみ食いするという意味です。
つまり、欲しいコミットだけとってくる、自分にとって都合のいい便利コマンドです。
cherry-pickの使い方
cherry-pickの使い方はとても簡単です。取得するコミットは1つだけ、または連続した複数のコミットを取得することができます。
自分のブランチで次のコマンドを実行します。
コミットを1つだけとってくる
$ git cherry-pick <欲しいコミット番号>
連続したコミットをとってくる
連続したコミットを取得する場合は、コミット番号の始まりと終わりを指定して..
で繋ぎます。
$ git cherry-pick <欲しいコミット番号(開始)>..<欲しいコミット番号(終了)>
コミット複数のコミットを指定してとってくる
連続していない複数のコミットを取得したい場合は、コミット番号の後ろにスペースを空けて、他のコミット番号を指定します。
$ git cherry-pick <欲しいコミット番号1> <欲しいコミット番号2> <欲しいコミット番号3>,,,,
実例
例として、リモートブランチのarticlesブランチの 15d340c70 というコミットを取得します。
▼欲しいコミット
(articlesブランチにて)
$ git log --oneline
15d340c70 (HEAD, origin/articles) [F]Article list
78f5c9911 [F]migration version
▼現在のローカルブランチのコミットログ
$ git log --oneline
3aebedb32 (HEAD -> test) [F]conflict schema.rb version
6e98e6c92 (origin/test) [F]article_rankings model and job
現在のローカルブランチのコミットの最新は 3aebedb32 です。この上に欲しいコミットを追加します。
cherry-pickの実行
git cherry-pickを実行すると、指定したコミットメッセージが表示されます。
$ git cherry-pick 15d340c70
[test 4a76eb1c6] [F]Article list_articles, html_article ArticleRanking
Author: xxx yyy <xxx+ouo@gmail.com>
Date: Fri Nov 19 19:06:29 2021 +0900
1 file changed, 52 insertions(+), 7 deletions(-)
ログを確認すると指定したコミットが一番上に来ていることが確認できます。
$ git log --oneline
4a76eb1c6 (HEAD -> test) [F]Article list_articles, html_article ArticleRanking
3aebedb32 [F]conflict schema.rb version
6e98e6c92 (origin/test) [F]article_rankings model and job
コミット番号は過去のコミットの影響を受けるので、指定したコミット番号 15d340c70 ではなく、新たに 4a76eb1c6 というコミット番号で追加されます。
cherry-pickのオプション
コミットメッセージを変更する(-e)
デフォルトでは元のコミットのコメントをそのまま持ってくる。
オプションで「-e」を指定することでコメントを変更できる。
git cherry-pick -e <コミット>
┗ -e = –edit
コミットはしない(-n)
デフォルトでは元のコミットまでされる。
「-n」オプションを指定することで、コミットせず、インデックス(git add)状態で持ってくることができる。
git cherry-pick -n <コミット>
┗ -n = –no-commit
空のメッセージを許可(–allow-empty-message)
デフォルトでは空のメッセージのコミットを持ってこようとするとエラーになる。
「–allow-empty-message」をつけることで、空のまま持ってくることができる。
git cherry-pick --allow-empty-message
処理をキャンセルする(–abort)
cherry-pickをなかったことにしたい場合は「–abort」をつける。
git cherry-pick --abort
おかしなことが起こった場合は一旦–abortで回避できる。
コミットを複数指定するときの原理
以下では参考として、コミットを複数指定する場合の原理についてまとめています。
コミットを個別に複数指定する場合
連続していない複数のコミットを取得したい場合は、コミット番号の後ろにスペースを空けて、他のコミット番号を指定します。
$ git cherry-pick <欲しいコミット番号1> <欲しいコミット番号2> <欲しいコミット番号3>,,,,
原理
例えば、以下のようにmasterブランチと、分岐したtopicブランチがあるとします。
A---B---C---D topic
/
D---E---F---G master
masterブランチにいるときに、topicブランチのコミットAとコミットCを取得したい場合は以下のようになります。
$ git cherry-pick A C ↓↓↓
master
D---E---F---G---A'---C'
A、CではなくA’、C’になるのは、後ろの履歴が変わったことで、コミットのハッシュ値が変わるためです。
連続するコミットを指定する場合
連続したコミットを取得する場合は、コミット番号の始まりと終わりを指定して..
で繋ぎます。
$ git cherry-pick <欲しいコミット番号(開始)>..<欲しいコミット番号(終了)>
原理
例えば、以下のようにmasterブランチと、分岐したtopicブランチがあるとします。
A---B---C topic
/
D---E---F---G master
masterブランチにいるときに、topicブランチのコミットAからCをまとめて取得したい場合は以下のようになります。
$ git cherry-pick A..C ↓↓↓
master
D---E---F---G---A'---B'---C'
A、B、CではなくA’、B’、C’になるのは、後ろの履歴が変わったことで、コミットのハッシュ値が変わるためです。
merge, rebase, cherry-pickの違い
他のブランチから新しいコミットを作成する主なコマンドに、merge, rebase, cherry-pickがあります。
ここでは参考としてそれらの原理の違いをまとめています。
merge
メインブランチとトピックブランチ両方のコミットをそのまま保持。
A---B---C topic
/
D---E---F---G master
$ git merge topic ↓↓↓
A---B---C topic
/ \
D---E---F---G---H master
rebase
トピックブランチのコミットをコピーしてメインブランチの先端に移動
A---B---C topic
/
D---E---F---G master
$ git rebase master ↓↓↓
topic
D---E---F---G---A'---B'---C'
master
cherry-pick
欲しいコミットだけをコピーし、メインブランチの先端に移動。
A---B---C topic
/
D---E---F---G master
$ git cherry-pick B ↓↓↓
D---E---F---G---B'
master