CH 27 / 75第4部 ブランチとマージ

cherry-pick で特定のコミットだけ運ぶ

このページで分かること

  • cherry-pick が「1つのコミットの変更を、今いるブランチに写す」操作だと説明できる
  • git log main..ブランチ で、運びたいコミットの ID を探せる
  • -x で、どのコミットから写したかを記録できる
  • cherry-pick を使うべき場面と、避けるべき場面が分かる
このページの目次9 items

23〜26では、ブランチのコミットをまとめて main に取り込みました。ただ、ブランチの中に「これだけは今すぐ main に欲しい」というコミットが1つだけ、ということもあります。このページでは、コミットを1つ選んで運ぶ cherry-pick(チェリーピック)を扱います。

cherry-pick は「変更を写し取る」#

cherry-pick は「さくらんぼを1粒ずつ摘む」という意味で、ほかのブランチにあるコミットを1つ選び、その変更だけを今いるブランチに新しいコミットとして写す操作です。ブランチ全体は取り込みません。

練習用のリポジトリで、献立を考えるブランチを作ります。途中で、献立とは関係のない買い物メモの追加も混ざってしまったとします。

text10 lines
cd ~/git-practice
git switch -c menu-plan
echo "月曜 カレー" > menu.txt
git add menu.txt
git commit -m "献立表を作成"
echo "バターを買う" >> shopping.txt
git commit -am "買い物メモにバターを追加"
echo "火曜 プリン" >> menu.txt
git commit -am "献立に火曜を追加"
git switch main

献立はまだ作りかけなので、ブランチごと取り込むわけにはいきません。でも、バターは今日買いに行くので、買い物メモの変更だけは main に入れておきたい。こういうときが cherry-pick の出番です。

運ぶコミットを探して、写す#

まず、運びたいコミットの ID を調べます。

text1 lines
git log --oneline main..menu-plan
text3 lines
a858a32 献立に火曜を追加
d2feb3d 買い物メモにバターを追加
e46ec1d 献立表を作成

26で使った main..menu-plan は、「menu-plan にあって main にないコミット」の範囲です。運びたいのは d2feb3d です。main にいることを確かめて、ID を指定します。

text1 lines
git cherry-pick d2feb3d
text3 lines
[main 40c666c] 買い物メモにバターを追加
 Date: Tue Oct 27 23:34:20 2026 +0900
 1 file changed, 1 insertion(+)

main に 40c666c という新しいコミットができました。Date: の行は、写したコミットが元のコミットの作成日時を引き継いでいることを示しています。

text1 lines
git log --oneline --decorate --graph --all -n 5
text6 lines
* 40c666c (HEAD -> main) 買い物メモにバターを追加
| * a858a32 (menu-plan) 献立に火曜を追加
| * d2feb3d 買い物メモにバターを追加
| * e46ec1d 献立表を作成
|/  
* 93a4042 じゃがいもを3個に
main とは別に、menu-plan ブランチに献立表を作成・買い物メモにバターを追加・献立に火曜を追加の3つのコミットがある。git cherry-pick d2feb3d で、バターのコミットの変更だけが main に新しいコミット deb9a28 として写される図
cherry-pick は、選んだコミットの変更だけを新しいコミットとして写す

同じ「買い物メモにバターを追加」が、main(40c666c)と menu-plan(d2feb3d)の両方にあります。menu-plan のほうは何も変わっていません。また、main には menu.txt は入っていません。

text1 lines
ls
text6 lines
config.txt
debug.log
recipes
shopping.txt
tmp
todo.txt

config.txt・debug.log・tmp は、第2部の12・13で除外したファイルなので、ブランチに関係なくワークツリーに残っています。

写した元を記録する:-x#

40c666c と d2feb3d は、中身が同じでも別のコミットです。あとから見て「これはどこから写したものか」が分かるように、-x を付けておくのがおすすめです。いったん今のコミットを取り消して、-x 付きでやり直してみます。

text3 lines
git reset --hard HEAD~1
git cherry-pick -x d2feb3d
git log -n 1 --format='%h%n%B'
text8 lines
HEAD is now at 93a4042 じゃがいもを3個に
[main deb9a28] 買い物メモにバターを追加
 Date: Tue Oct 27 23:34:20 2026 +0900
 1 file changed, 1 insertion(+)
deb9a28
買い物メモにバターを追加

(cherry picked from commit d2feb3d24ec6092696377f1c560a3ddd57acf11f)

メッセージの末尾に (cherry picked from commit …) が書き加えられました。--format='%h%n%B' は、短い ID とメッセージ全文を表示する指定です(第2部の11)。

写し済みかを確かめる#

menu-plan のコミットのうち、どれが main に写し済みかは git cherry で確かめられます。

text1 lines
git cherry -v main menu-plan
text3 lines
+ e46ec1df73e8df735dcd553d4cf757d4432c1e19 献立表を作成
- d2feb3d24ec6092696377f1c560a3ddd57acf11f 買い物メモにバターを追加
+ a858a32716fe51948ae4218e0e6c4b963d258edd 献立に火曜を追加

- が「同じ変更が main にもうある」、+ が「まだない」です。ID は違っても、変更の中身を比べて判断しています。

片付けと、コンフリクトしたとき#

献立の案は、今回は取り込まずに捨てることにします。

text1 lines
git branch -d menu-plan
text3 lines
error: the branch 'menu-plan' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D menu-plan'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

バターのコミットを写していても、menu-plan のコミットそのものは main に入っていないので、-d は断ります(22)。捨てると決めているので、-D で消します。

text1 lines
git branch -D menu-plan
text1 lines
Deleted branch menu-plan (was a858a32).

cherry-pick でも、写す変更が今いるブランチの内容とぶつかればコンフリクトします。止まったときの直し方は24と同じで、ファイルを直して git add までは共通です。そのあとは cherry-pick 用のコマンドを使います。

コマンド動き
git cherry-pick --continue直した内容でコミットを作る
git cherry-pick --skipこのコミットを写すのをやめて、次へ進む(複数を写しているとき)
git cherry-pick --abortcherry-pick を始める前の状態に戻す

使うべき場面・避けるべき場面#

使うとよい場面避けたほうがよい場面
作業ブランチの中の、急ぎの修正だけを先に main へ入れたいブランチのコミットをいくつも運びたい(マージや rebase を使う)
間違ったブランチでコミットしてしまったので、正しいブランチへ移したいあとでそのブランチも丸ごとマージする予定がある
古いバージョンのブランチに、main で直したバグ修正だけを入れたい

cherry-pick で写したコミットは「同じ変更を持つ別のコミット」なので、元のブランチをあとでマージすると、同じ変更が履歴に2回現れます。たいていは Git がうまく重ねてくれますが、そのあとで同じ行をさらに変えているとコンフリクトの原因になります。cherry-pick は「その1つだけ」が欲しいときの道具で、ブランチ同士をつなぐのはマージや rebase の役目です。

よくある疑問#

Q. 複数のコミットをまとめて cherry-pick できますか?
A. できます。git cherry-pick ID1 ID2 のように並べると順に写します。git cherry-pick A..B と範囲で指定すると、A の次から B までを写します(A 自体は含まれません)。ただ、たくさん運ぶなら、マージや rebase を検討してください。

Q. コミットせずに、変更だけをワークツリーに持ってくることはできますか?
A. -n(--no-commit)を付けると、変更をワークツリーとステージに反映するだけで、コミットは作りません。中身を確かめてから自分でコミットしたいときに使います。

まとめ#

  • cherry-pick は、ほかのブランチのコミットを1つ選び、その変更を今いるブランチに新しいコミットとして写す
  • git log --oneline main..ブランチ で運びたいコミットの ID を探し、運びたい側に立って git cherry-pick ID
  • 写したコミットは ID が違う別のコミット。-x で写した元を記録しておくとよい
  • git cherry -v で、写し済みかどうかを確かめられる
  • ブランチ同士をつなぐのはマージや rebase。cherry-pick は「その1つだけ」が欲しいときに使う

次のページ#

28. ブランチ戦略(GitHub Flow / Git Flow / trunk-based) ── 第4部のしめくくりとして、ブランチをどう切り、どう取り込むかのチームの決めごとを3つ比べます。