読みやすいgitログは未来の自分へのプレゼント

    読みやすいgitログは未来の自分へのプレゼント

    目次

      こんにちは、DE部GE課の松浦です。
      git使ってますか、git。
      共同作業で開発する場合、gitを使うことはもはや必須となっており、gitのログを読むことも多いと思います。
      たとえば特定の問題が発生したときに、どのように変更したかは、gitのログを見ることで確認できます。
      しかしコミットが非常に細かく分断されていたり、コミットメッセージがわかりにくい場合、ログを読むのが大変になります。
      そこで、今回はgitのログを読みやすくするためのテクニックを紹介します。 未来の自分に見やすさをプレゼントしよう。

      コミット操作で見やすくする

      コミットメッセージを変更する

      これはよくあり得ると思います。
      コミットした後に、コミットメッセージが思っていたよりも分かりづらく、自身でメッセージを直したいときです。
      そういったときは、以下のコマンドで直近のコミットメッセージを修正できます。

      git commit --amend

      gitのコミットメッセージは、なるべく分かりやすく具体的に何をなぜやったかがわかるように書かれていると良いですね。

      複数のコミットを一つにまとめる

      一時的にコミットして、あとでまとめたいときありますよね。
      そういったときは後述するStashを利用しても良いのですが、一度wip等でコミットした後にコミットを1つにまとめる方法も有効です。

      git rebase -i HEAD~nを利用することで、複数のコミットに対して、さまざまな処理ができます。
      rebaseは編集中のファイルが存在していると使えないので、一度ブランチをきれいにしてから実施しましょう。
      不要なファイルであればgit reset --hard HEADでリセットしたり、git stashを利用して、一時的に保存させておくと良いです。

      rebaseを実行すると、n個分のコミット一覧が表示されます。
      この画面では、fixup/squashを利用してコミットをまとめたりできます。

      fixup/squashを利用する

      デフォルトでは表示されたコミットはすべてpick(p)になっていると思うので、1つにまとめたいコミットの下にある複数のコミットに対してfixup(f)の指定をします。
      fixupを利用することで、コミットを1つ前のコミットにまとめることができます。

      squashも基本的な動作はfixupと同じなのですが、コミットメッセージを残すかどうかが異なります(説明のとおりですね)。

      また、以下のような説明も表示されると思います。
      書いてあるとおり、他にも各コミットに対してrenameを実施したり、コミットの内容を編集することも可能ですが、今回はfixup/squashのみの紹介となります。

        5 # Commands:
      6 # p, pick <commit> = use commit
      7 # r, reword <commit> = use commit, but edit the commit message
      8 # e, edit <commit> = use commit, but stop for amending
      9 # s, squash <commit> = use commit, but meld into previous commit
      10 # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
      11 # commit's log message, unless -C is used, in which case
      12 # keep only this commit's message; -c is same as -C but
      13 # opens the editor
      14 # x, exec <command> = run command (the rest of the line) using shell
      15 # b, break = stop here (continue rebase later with 'git rebase --continue')
      16 # d, drop <commit> = remove commit


      ブランチを最新のdevelopから生え直させる

      数日前にdevelopから新しいfeatureブランチを切って、developにマージしようとしたらdevelopに更新が入っていたといったケースはありませんか?
      私はあります。この場合に役に立つのが、ブランチを最新のdevelopから生え直させる方法です。
      これは、-iオプションを付けないrebaseで実現可能です。

      git rebase origin/develop <最新のdevelopにずらしたいブランチ> 
      (リモートをoriginとして設定している場合を想定しています)

      rebaseを行うことで、developからかなり長い線が出るのを防げます。
      ただし問題点もあり、developにマージされたコミットが自分の変更内容と被る場合、当然ですがrebase時にコンフリクトが発生します。


      pushしてしまった後にコミットを修正する場合

      すでにコミットをpushしてしまっている場合は、ローカルで編集した履歴とリモートとの履歴で差分が生じるので、pushできなくなります。
      過去のデータを編集しているので、辻褄が合わなくなっているためです。
      この場合は強制プッシュgit push -fを行い、リモートの履歴を上書きをすることで解決できます。
      ただし、他の人が同じブランチを利用している場合は、基本的に強制プッシュは避けるべきです。状況によって実施するかを考えましょう。 
      --force-with-leaseで強制プッシュを行うこともでき、こちらはリモートよりもローカルの履歴が新しい場合のみ更新できるので、安全です。

      参考:force-with-lease

      開発体制や対応しているブランチによって、強制プッシュを行うかどうかの判断は変わると思います。
      たとえば、チケット駆動で開発している場合、基本的に自身のチケットで他の人が対応しているケースは少ないと思われるので問題は起きないと思いますが、
      developで作業しているケース等であれば、なるだけ強制プッシュは避けるべきです。

      stashを活用する

      コードを書いている際、他のブランチに移って動作チェックとかをしたいとき、ありますよね(断定)。
      WIPコミットをまとめる方法は紹介しましたが、このパターンだとまとめるのを忘れてpushしてしまうよ!
      という方はstashを利用すると良いです。

      stashとはズバリ、作業中の変更を一時的に保存するための機能です。
      よく退避と言われますが、自分的には一時保存の方がしっくりきます。クイックセーブとも言えるかもしれません。
      要領としてはコミットするときとほぼ同じで、タイトルを入れてgit stash or git stash pushを実行するだけ。 
      git stash saveでもstashを保存できますが、バージョン2.16.0からsaveは非推奨となっているので、pushを使うことをオススメします。

      参考:2.16.0リリースノート
         git stash save

      また使いたくなったときはgit stash applyで適応できる。削除も同時にしたいならgit stash pop
      自分の場合は、あとで見直したいときとかが発生するケースがあったのでapplyをよく使っています。

      stashの注意点として、あくまでもローカルに保存しているだけなので、PCを変更したりしたらstashは引き継がれません。
      ローカル環境を削除した場合も当然stashは消えてしまうので、注意してください。

      コミットログに一定のルールを設ける

      チーム全員が同じルールでコミットログを書くことで、コミットログの読みやすさを向上させます。

      言語を統一する

      コミットログを英語と日本語のどちらで書くか問題があります。
      これはチーム内で決めればよいことなのですが、どちらでも良いという場合は誰が読むかわからないので英語で書くほうが良いと思います。


      コミットメッセージにテンプレートを設ける

      コミットログに一定のルールがあると、パット見でどのような変更が入っているかがわかりやすくなります。
      とくに、接頭詞として変更の種類を示すことで、どのような変更が行われたかが一目でわかるようになる点は大きいです。
      ルールはチーム内で決めてもよいのですが、巨人の肩に乗る方が楽なので、自分は既存のルールを利用することをオススメします。

      ここでは一番メジャーであろう、Conventional Commitsを紹介します。
      こちらはAngularJSのコミットメッセージのルールをベースにした、以下のフォーマットでコミットメッセージを書く規約となります。

      <型>[任意 スコープ]: <タイトル>

      [任意 本文]

      [任意 フッター]

      引用:Conventional Commits 1.0.0

      まとめ

      今回紹介した内容を活用することで、未来の自分やチームメンバーがログを読むときに救われます。
      まずは明日、次のコミットから試してみましょう。未来の自分を救うのは、今の自分だ。

      アジアクエスト株式会社では一緒に働いていただける方を募集しています。
      興味のある方は以下のURLを御覧ください。