この記事は、ジーズアカデミー 技術記事書いてみた編 Advent Calendar 2023の12日目の記事です。
gitのコマンドの中で、個人的に「git cherry-pick
」は上級者向けだなーと思っているのですが(僕は上級者ではない)、最近ようやく少しだけ人に説明できるレベルになれた気がするので、さらに自分の中で昇華させるためにブログ記事にしたいと思います!
目次
git cherry-pickとは何か?
この記事に辿り着いた方の中には、git cherry-pick
についてご存知の方もいらっしゃるかとは思いますが、git cherry-pickとは何かについて書いておきたいと思います!
git cherry-pick
は、別ブランチから特定のコミットを取り込みすることができるコマンドと説明されています。
色々なサイトで説明されているgit cherry-pick
の使用事例として
- バグ修正の取り込み
- 機能の部分的な統合
- コードレビューの修正の適用
というのが挙げられます。
僕はこのgit cherry-pick
コマンドがなかなか理解できず、git cherry-pick
の使用事例を見ても全くピンとこない期間が長いことありました。
なぜgit cherry-pickが難しいのか?
(これはあくまで僕の意見です)
そんなこんなで難しいgit cherry-pick
なんですが、なぜgit cherry-pick
が難しいのか?
それは、git cherry-pick
を使いこなす上で、コミットを適切に行うことが大前提として必要になるというのがあり、その認識がないとgit cherry-pick
の有用性を感じにくいからだと思っています。
コミットとは?
さて、コミットとはなんでしょうか?gitは基本的に「コードの変更記録を保存していく」ものです。その変更記録の1つ1つのことを「コミット」と呼びます。
コミットには通常
- いつ
- 何の作業(修正とか追加とか削除とか)を
- 何の根拠に基づいて(これは僕の見解もあると思いますが)
行ったのかを記録していきます。
コミットの難しさ
このコミットの粒度(どれくらいの作業単位でコミットするのか)は非常に難しい問題で、インターネット上を回遊してみても、実にさまざまな見解や議論の記事を見つけることができます。
どんなコミットの仕方がベストなのかということはさておき、最低限気をつけるべきこととしては「実際にコード(ファイル)を編集した内容と。記録した内容にしっかりと整合性が取れている」という点があるのではないかと思います。
例えば、「ログインページ」と「トップページ」の作成をするとします。整合性のとれたコミットの仕方をしていないと、
- 記録上は「トップページの作成」となっている
- でも実際に作成(編集)されたコード(ファイル)はトップページとログインページの内容が両方含まれている
という状態が発生し、記録と作成された内容に整合性が取れないという状況が発生してしまいます。
そういった整合性が取れないコミットの仕方をしてしまっていると、git cherry-pick
の有効性が体感できないのだと思いました。
整合性の取れないコミットの仕方をしてしまっていると、「トップページの機能は取り込みたいけどログインページの機能は取り込みたくない」のに、「トップページの機能とログインページの機能がが両方同じコミットに混ざってしまっている」ため、希望通りの取り込みの仕方ができない状態になってしまったりするので…。
コミットの単位
ということで、コミットする単位は重要だということは何となく掴んでいただけたら嬉しいのですが、じゃあどれくらいの粒度でコミットすべきかというのは本当に難しい問題です。
かくいう僕は、コミットの粒度が本当に下手くそでいつも悩むところなのですが…
インターネット上を回遊してみると、コミットの粒度に関する色々な記事があってどれも参考になります。
そして、自分なりの感覚にはなってしまうのですが、最低限、以下の点を考慮してコミットの粒度を決めていくのがいいのではないかと思いました。
- 大前提として、先ほど掲載したように「コード(ファイル)を編集した内容と。コミットに記録した内容にしっかりと整合性が取れている」状態を作る。
- 基本的にはコミットは機能単位で考え、1コミットごとに中途半端な状態(例えばプログラムが動かない状態のままコミットする)ことはしない。(どうしてもハマって抜け出せないなど何らかの理由がある場合はWIPを頭につけた状態でコミットメッセージを作るのが一般的?)
- 大量の内容を1コミットに含めない。(レビューしてもらう人など、他の人が見る際に内容の確認や理解をするのが大変になってしまうので)。また、機能に対して変更量が多い場合は、分割も考える。
git log --online
コマンドでコミットのログ一覧を見た時に、変更記録が読みやすく見やすい状態になっていることを意識する。(メッセージ内容がいまいちであれば後で修正もできなくはないので…)
要するに、矛盾がなく、人が見たときに読んだり理解したりするのがしんどくない、という視点を忘れないことが重要なんだろうなと思います….頑張れ自分!
機能単位のコミット、の難しさ
難しいなと思うのが「機能単位」でのコミットです、
例えば、大袈裟にいうならば「ログイン処理」も1つの機能になるわけですが、ログイン処理を実装する上でのコード変更範囲が大量にある場合、それを全部1コミットに含めてしまうと、結局コードを他の誰かや将来の自分に見てもらう際に、即座に内容が理解しにくい状態になることは容易に想像ができます。
なので、ログイン処理に関連する部分を複数のコミットに分ける場合は、
- UI部分の実装
- 認証処理(DBに入っているユーザー名とパスワードと合致するかどうか)
- トークン生成
- リファクタリング
みたいな感じで、エラーが起きない単位でかつ意味のある分け型をするのが望ましいように思いました。
git cherry-pickの使い方
さてさて、そんなこんなでgit cherry-pickの使い方についても書いておきたいと思います!
前提として
- branch1・・・取り込みたいコミットが含まれているブランチ
- branch2・・・cherry-pickを実行したいブランチ
という前提でお話を進めていきたいと思います!
1. 取り込みたいコミットのログを確認する
git checkout branch1
git log
branch1にいる状態にして、git logコマンドを実行します!
git log
を実行すると、コミットのリストが表示されるので。取り込みたいコミットを見つけ、そのコミットハッシュ(通常は40文字の長い英数字)をコピーします。
2. cherry-pickを実行したいブランチ
にチェックアウトする
次に、cherry-pick
を実行したいブランチ(この場合は branch2
)にチェックアウト・切り替えをします。
git checkout branch2
3. cherry-pick
コマンドを実行する
1でコピーしたコミットハッシュをcherry-pickコマンドに添えて実行します!
git cherry-pick [コミットハッシュ]
これで取り込み自体は完了です!
ちなみに、
git cherry-pick -n [コミットハッシュ]
とすると、内容は取り込みするけどコミットは残さないという状態を作ることもできます!
まとめ
ということで、今回は「git cherry-pickとコミットの作り方はセットで考える & 覚える」という内容でお送りしました!!!!