Zenn
🍴

インタラクティブリベースで統合したコミットを、解剖

に公開

はじめに

普段の開発でPR(Pull Request)を作成する際には、コミット履歴を整理して、レビュワーや未来の保守運用者(自分?)のために理解しやすいプロジェクト履歴を残すことを目的として可能な限り1つのPRに対して少ないコミット履歴になるよう、git rebase -iを用いてコミット履歴を統合しています。
ただ、技術ブログにまとめたいと思っていた内容のコミットも一旦リベースしてPRを作ったため、いざ技術ブログをまとめようとした際に、どこのコミットに対象の差分があったか迷子になってしまいました。
そこで、統合したコミットから対象のコミットを探し出すフローと注意点みたいなものをまとめられたらなと思っています。

想定対象読者

  • Git Biginners
  • Git考古学 Biginners
  • 統合前のコミット履歴を再確認したい方

git rebase -iの基本

インタラクティブリベース(git rebase -i)は、Gitの強力な機能で、コミット履歴を整理・再編成できます。これにより、複数のコミットを統合したり、コミットの順序を変更したり、コミットメッセージを修正したりすることが可能です。

インタラクティブリベースの基本的な使い方

  1. コマンドの実行

    git rebase -i <ベースコミット>
    

    <ベースコミット>は、変更したいコミットの直前のコミットを指定します。例えば、最新の3つのコミットを操作したい場合は以下の通りです。

    git rebase -i HEAD~3
    
  2. エディタが開く
    コマンドを実行すると、テキストエディタが開き、指定した範囲のコミットがリストアップされます。

    pick abc1234 最初のコミットメッセージ
    pick def5678 2つ目のコミットメッセージ
    pick ghi9012 3つ目のコミットメッセージ
     
    # Rebase コマンドのヘルプメッセージ...
    
  3. 操作の指定
    各コミットの行の先頭にあるキーワード(デフォルトではpick)を変更して操作を指定します。主な操作は以下の通りです。

    • pick: コミットをそのまま使用
    • reword: コミットを使用し、メッセージを変更
    • edit: コミットを使用し、コミット内容を修正
    • squash: 前のコミットに統合し、両方のメッセージをマージ
    • fixup: 前のコミットに統合し、このコミットのメッセージを破棄
    • drop: コミットを削除
  4. 変更の確定
    エディタを保存して閉じると、Gitが指定された操作を実行します。いつでもgit rebase --abortでリベースを取り消せるのでカジュアルに統合しちゃってください。

Squashを用いたコミットの統合の流れ

それでは、複数の小さなコミットを1つの意味のあるコミットにまとめる方法を説明します。

  1. リベースの開始
    まとめたいコミットの範囲を指定してリベースを開始します。

    git rebase -i HEAD~4  # 最新の4つのコミットを操作
    
  2. エディタでの操作

    pick abc1234 メインの機能実装
    squash def5678 バグ修正
    squash ghi9012 テストの追加
    squash jkl3456 ドキュメント更新
    

    この例では、最初のコミット以外を全てsquashに変更し、1つのコミットにまとめます。

  3. コミットメッセージの編集
    エディタを保存すると、新しいコミットメッセージを入力するためのエディタが開きます。ここでは、全てのコミットメッセージが表示されるので、必要に応じて編集します。

  4. 完了
    メッセージを保存すると、4つのコミットが1つのコミットに統合されます。

統合したコミットの内部構造を解剖

そこで問題になったことが、コミットを統合してしまったが故に、統合前のコミットでどんな変更を行ったかを確認することに苦労したことです。
図で示している部分で説明すると、「バグ修正」のコミットにあたります。このコミット時に行った作業について記事にまとめたかったのですが、リベースしていたため、差分迷子になっていました。
対象のコミットの内容を確認するため、インタラクティブリベースで統合したコミットを解剖していきいます!

  1. リベース前コミットメッセージ探索
    リベースしたコミットログから対象のリベース前のコミットメッセージを探し出します。特に私のように、コミットしてからしばらく経ってから探し出そうとする場合は、おそらくここが最初のステップしにて最も根気が必要な作業になるかと思います。
    GUIツールもしくはgit log --pretty=fullコマンド等を利用して確認すると、以下のような出力を得ることができます。「バグ修正」というそれらしきコミットメッセージの存在を確認。

    機能実装
    
    バグ修正
    
    テスト追加
    
    リファクタリング
    
  2. Reflogを用いたコミットハッシュの取得
    Gitは操作履歴をreflogとして記録しています。リベース前の状態も残っているので、git reflogで確認します。

    git reflog
    

    出力される結果から手動で探し出すのもよし。grepして取得するのもよしだと思います。結果からコミットハッシュが確認できるので、コピーしておきます。

  3. 元のコミットを確認する
    発見した「バグ修正」のコミットハッシュを使って、以下のようにコマンドを打つことで、そのコミットで行った差分を確認できます。

    git show <commit_hash>
    

無事、求めていた差分を確認できました!

まとめ

インタラクティブリベースで統合したコミットの、リベース前のコミットを確認したい場合の手順をまとめました。
たまに、インタラクティブリベースですぐにコミットを統合することが分かっている場合、よくコミットメッセージをhogehogeとかにしてしまうことがあるのですが、今回はたまたまリベース前のコミットにも意味のあるコミットメッセージを付与していたおかげで時間をかけずに探索することができました。どんな場合でもしっかりコミットメッセージを残すことの重要性を改めて感じた機会となったと思います。
また、squashの代わりにfixupを用いて前のコミットのメッセージを破棄してしまった場合も探索できなくなってしまうため、基本はsquashでまとめる方が後々助かることがあるかもしれないですね。ただ、コミットルールはその開発組織の哲学による部分も少なからずあると思うので、是非様々な開発組織でのコミット哲学を聞いてみたいですね!

参考リンク

  1. Git - git-rebase Documentation
  2. Write Better Commits, Build Better Projects - The GitHub Blog
  3. git rebase | Atlassian Git Tutorial
  4. Git Rebase --interactive: EXPLAINED
  5. git rebase - Why, When & How to fix conflicts

Discussion

ログインするとコメントできます