git cherry コマンドを活用しよう!
git cherry
コマンドをご存知だろうか?
git cherry-pick
は他のブランチ上の特定コミットを自分のブランチへ取り込むコマンドであるが、取り込んだものは別のコミットIDが与えられる。何度も cherry-pick を繰り返していると、取り込み済みのものと、まだ取り込んでいないものがわからなくなる。
それをチェックするのが git cherry
コマンドだ!
git log
でブランチ間のコミットを比較する
まずは、コミットログの差分をとってみよう。
下記コマンドにて カレントブランチHEAD
のコミットログのうち、ブランチorigin/debug-work
のログに含まれていない、3つのコミットが差分として出る。
$ git log --oneline origin/debug-work..HEAD
ed079ea (HEAD -> master, tag: rel-master, origin/master, origin/HEAD) Feat: use dfnas
3a4fe94 Feat: refine moveYYYY
0980bb3 Feat: install dfnas
だが、上記コミットのいくつかは cherry-pick で取り込んだものである。
git cherry
でブランチ間のコミットを比較する
git log
では cherry-pick で取り込んだものか否かがわからない。
そこで git cherry
の出番である。
$ git cherry -v origin/debug-work HEAD # 第二引数HEADは省略可
- 0980bb30bd4d2e6a0e23bb992e6f5a01ad34abff Feat: install dfnas
- 3a4fe949a5b43af24cecde8b2a85d7d4fc230410 Feat: refine moveYYYY
+ ed079eaef5c768a0d3869f4d2e99060ec2e23c3e Feat: use dfnas
行頭に "-" が付いているものは cherry-pick で取り込み済みのコミットである。
行頭に "+" が付いているものは HEAD側にのみ存在するコミットである。
両者が共通に持つコミットは表示されない。
$ git cherry -v HEAD origin/debug-work
+ d5ae5df177a936d4db6a05330657efb054073045 test for memoryleak
- 0980bb30bd4d2e6a0e23bb992e6f5a01ad34abff Feat: install dfnas
- 3a4fe949a5b43af24cecde8b2a85d7d4fc230410 Feat: refine moveYYYY
引数の順番を入れ替えると、
origin/debug-work側にのみ存在するコミットに対して行頭に "+" が付くので、
欲しいコミットをHEADへ取り込んでいけば良い。
ブランチ管理への応用
git cherry
の出力が多くなったら、比較対象ブランチやカレントブランチを、両者の祖先ブランチへマージ・リベースすべき兆候と考える。
大量に積みあがったコミットを1つのプルリクエストとして処理するのは大変なので、区切りの良い箇所で分割して小さい単位で管理したほうが良い。その判断に利用できる。出力行数で判断できるので自動化も簡単である。
また、ブランチの分岐状況を調べたい場合に、ツールを使って分岐ツリーグラフを見るよりも、git cherry
でコミット比較を見た方が簡潔である。
git cherry
はマイナーだが、実はかなり使えるコマンドだと思う。
最後に一言
git cherry
はかなり使えるコマンドであるが、そもそもマージやブランチを先延ばしにするのは良くない。
git rebase
は、別コミットIDであってもコミット内容が同一であれば、リベース先のコミットIDを残してカレントブランチ側のコミットIDを捨てるので、衝突せずにうまい具合に処理してくれる。
よって、リベース先のコードが安定したら、さっさとリベースするほうが楽であることを覚えておいてほしい。
【おまけ】git cherry コマンドの公式ドキュメント
上記が公式ドキュメントですが、言い回しや用語がわかりにくいので、意訳したものを以下に貼っておきます。
NAME
git-cherry - 上流ブランチに取り込まれていないコミットを見つける
SYNOPSIS
git cherry [-v] [<upstream> [<head> [<limit>]]]
DESCRIPTION
比較元である<limit>..<head>
範囲内に、比較先の<head>..<upstream>
範囲内と同等のコミットがあるか判定します。
同等判定は、空白と行番号を削除した後の diff に基づいて行います。そのため、git cherry-pick, git am, git rebase
によって コピー されたコミットが検出されます。
<limit>..<head>
範囲内のコミットハッシュを出力し、<upstream>
に同等のコミットがあれば先頭に-
を、なければ先頭に+
を付けます。
OPTIONS
-v
コミットタイトルを、コミットハッシュの後に示します.
upstream
同等コミットを探す先である比較先ブランチ. 省略時は HEADの上流ブランチ を用いる.
head
比較元の作業ブランチ. 省略時は HEAD を用いる.
limit
比較元から除外したいコミットの末端.
※ 公式記載がないが、省略時は head から遡った全履歴が比較先となる. upstream と head が共通の祖先を持たない場合に limit を省略すると head の全履歴が "+" で表示されることになる.