こんにちは、ひろきです。
現在、フィヨルドブートキャンプ(以下、FBC)で学習しています。
突然ですが、皆さんは無駄なコミットをしていますか?私はしていました。
ここで言う無駄なコミットとは、レビューをもらう際に見てもらう必要のないものを指します。
私の場合、課題を提出する際、機能に関するコミットをした後、RuboCopやESLint、Prettierを通すことを忘れていて、決めの「RuboCopを通しました」的なコミットをずっと残していました。
今回もそれをメンターさんにご指摘いただいたことで新しい学びとなりました。
他の人が変更内容を見ても変更履歴として得られる情報がない
上記のようなコミットは粒度を変えてまとめる必要があります。
したがって、本記事ではコミットをまとめる方法を紹介します!
TL;DR
git rebase -iで、関係するコミット同士を並び替えた後、必要なコミットの下に不要なコミットを置いて、pickをsquashに変え保存します。
git push origin <あなたのブランチ>でpushできない可能性が高いので、git push -f origin <あなたのブランチ>で強制プッシュをします。
強制プッシュをする場合は注意が必要です。
それでは、具体的な説明に移ります。
コミットを整理する流れ
git rebase -iでコミットを表示する
git rebase -hで解説をみます。
-i, --interactive let the user edit the list of commits to rebase
「リベースするコミットの一覧をユーザーが編集できるようにする。」
とあります。
コミットの一覧を表示するために、どのコミットかを指定する必要があります。
直近のコミットからn個遡ったコミット一覧を表示し、編集するコマンドは以下です。
git rebase -i HEAD~n
直近からn個目のコミットが全て表示されます。
以下は、3つの事象(A、B、C)を開発した場合のコミットでgit rebase -i HEAD~7をした際の結果です。
pick a1b2c3d Aを追加 #1 pick d4e5f6g Aの整形をした #2 pick h7i8j9k 改行をした #3 pick l0m1n2o Bの修正 #4 pick p3q4r5s Cの修正 #5 pick t6u7v8w Bで改行を増やした #6 pick x9y0z1a Cの調整 #7
ここで不要なコミットは4つあります。
他の人が変更内容を見ても変更履歴として得られる情報がない
を参考にすると、「#2」、「#3」、「#6」、「#7」が情報として得られるものがありません。
今回の例ではコミットメッセージが雑なので、例として良くないかもですが、「#4」や「#5」は本来であれば「◯◯を△△にするため修正」のようにしているはずなので、必要な情報です。
特定のコミットから表示したい場合(クリックで表示)
git rebase -i コミットID^
これで、そのコミットから先のコミットが表示されます。
関連するコミットを上下に配置する
「#2」、「#3」、「#6」、「#7」のコミットがそれぞれどのコミットに関するものかを考えます。
pick a1b2c3d Aを追加 #1 pick d4e5f6g Aの整形をした #2 pick h7i8j9k 改行をした #3 pick l0m1n2o Bの修正 #4 pick p3q4r5s Cの修正 #5 pick t6u7v8w Bで改行を増やした #6 pick x9y0z1a Cの調整 #7
#2と#3は「#1」、#6は「#4」、#7は「#5」のものだとわかります。 なので、以下のように順序を入れ替えます。
pick a1b2c3d Aを追加 #1 pick d4e5f6g Aの整形をした #2 pick h7i8j9k 改行をした #3 pick l0m1n2o Bの修正 #4 pick t6u7v8w Bで改行を増やした #6 pick p3q4r5s Cの修正 #5 pick x9y0z1a Cの調整 #7
今回は、#5と#6が入れ替わりました。
不要なコミットをsquashに変更する
squashについての説明をhelpコマンドで見つけられませんでした。
squashは「押しつぶす、ぺちゃんこにする」という意味なので、言葉通りコミットをぺちゃんこにします。
不要なコミットのpickをsquashに変更してください。
pick a1b2c3d Aを追加 #1 squash d4e5f6g Aの整形をした #2 pick h7i8j9k 改行をした #3 pick l0m1n2o Bの修正 #4 squash t6u7v8w Bで改行を増やした #6 pick p3q4r5s Cの修正 #5 squash x9y0z1a Cの調整 #7
変更をしたら、保存をしてください。
(Vimが開かれているので、「編集できないぞ!」という方はiを押して編集モードにしてください。編集が完了したら、escでノーマルモードに戻し、:wqで保存ができます。)
コミットメッセージを編集する
まだ終わっていません。コミットメッセージを編集できます。
以下はChatGPTに出してもらった編集画面です。
# This is a combination of 2 commits. # The first commit's message is: Aを追加 # The commit message #2 will be merged into the first: Aの整形をした # Please enter the commit message for your changes.
となるので、もし、「Aの整形をした」が不要であるならば、先ほどと同様に編集モードで削除をし、保存をしてください。
pushします
コミットをスッキリさせることができたので、プッシュをします。
しかし、リモートにある履歴が異なるのでエラーが発生するかもしれません。
その場合は、強制プッシュをします。
git push -f origin <あなたのブランチ>
これで強制プッシュができます。
個人で作業している場合は特に難しいことを考えなくて良いかもしれませんが、チームで開発をしている場合、他人のコミットを消してしまう可能性があるので、注意が必要です。
亀さんペースでこの記事を書いている間に、チーム開発のプラクティスに到達しました。
そこで
git push --force-with-lease origin <あなたのブランチ>
を知りました。
git push -fとの違いは、-fは容赦無くプッシュをしますが、--force-with-leaseではプッシュする対象が最新ではない場合にエラーを起こしてくれるというものです。
現実でも、変更があったときに勝手に新しい変更を加えられたら迷惑ですよね。便利!
参考:git push -f をやめて --force-with-lease を使おう #Git - Qiita
その後、GitHub等で変更を確認してください。
終わりに
以前、コミットの粒度についての記事を書きましたが、その時にコミット数が莫大になると思いました。
「粒度を小さくコミットする人VS適度な粒度が良い人」みたいな構図があった場合、「どうなるのだろう?」と言う気持ちがあったので、今回のアドバイスで解決することができました。
今回のアドバイスで、コミットの粒度の感覚が少しわかったような気がします。
これから私もチーム開発でコードレビューをすることがあると思うので、「コミット」の重要性をより実感していくのかと思うと、ワクワクとドキドキでいっぱいです。