Git Rerere: マージコンフリクトの二度手間を解消する

Git tutorial - IT technology blog
Git tutorial - IT technology blog

手動作業は卒業:Gitにコンフリクト解消を「学習」させる

長期間運用しているフィーチャーブランチをrebaseしているとき、同じコンフリクトを5〜6回も解消し直した経験はありませんか?あの作業は非常にストレスが溜まるものです。Git Rerere(Reuse Recorded Resolution)は、まさにその悩みを解決するために生まれました。簡単に言えば、コンフリクト解消を一度だけ行えば、Gitがその方法を学習し、次回同じ状況が発生した際に自動で適用してくれる機能です。

この機能の有効化は非常に簡単です。以下のコマンドを一度実行するだけです:

bash\ngit config --global rerere.enabled true

有効化すると、Gitはファイルの修正前後の状態をバックグラウンドで記録し始めます。特定のプロジェクトだけで試したい場合は、グローバル設定を変更する代わりに、プロジェクトの.gitディレクトリ内にrr-cacheというフォルダを作成してください:

bash\nmkdir .git/rr-cache

実例ケーススタディ:1人のリファクタリングが、チーム全員の悲鳴に

以前、200以上のロジックファイルを持つ大規模プロジェクトを8人のチームで担当していました。私は中心となる設定ファイルの構造全体をリファクタリングするタスクを引き受けましたが、その間も他のメンバーは各々のブランチで新機能のコードを次々とプッシュしていました。

悪夢が始まったのは、リファクタリング後のコードをmasterにマージしたときです。残りの7人がrebaseを行う際、すべてのコミットで設定ファイルに同じ種類のコンフリクトが発生してしまいました。中には50回も同じコンフリクトに直面したメンバーもいました。一つずつ手動でAccept Incomingをクリックする代わりに、チーム全員にRerereを有効にするよう伝えました。その結果、最初の1回を解消しただけで、残りの49回はGitが数秒で自動的に処理を完了させたのです。

このテクニックは、特に以下の2つのシチュエーションで威力を発揮します:

  • 頻繁なリベース: 自分のブランチを常に最新のmasterに追従させたいが、修正中のコード領域でmasterの変更が激しい場合.
  • テスト用マージ(Test merges): テスト実行のために一時的にブランチをマージしたいが、まだコミットはしたくない場合。一度コンフリクトを解消してテストし、その後にabortしても、次回の本番マージ時に同じ修正を繰り返す必要がなくなります。

PreimageとPostimage의 仕組みとは?

Gitが勝手にコードを修正して壊してしまうのではないかと心配する人もいるでしょう。しかし、その仕組みは非常に透明性が高いものです。コンフリクトが発生し、Rerereが有効な場合、Gitは以下の3つのステップを実行します:

  1. Preimageの保存: Gitは、<<<<<<<======= などのマーカーが含まれた状態のファイルを記録します。
  2. ユーザーによる修正: IDEなどでコードを修正し、コンフリクトマーカーを削除して保存します。
  3. Postimageの保存: git add を行った瞬間に、Rerereはそのクリーンな状態を「正解のテンプレート」として保存します。

次回、Gitがコンフリクトファイルを検知し、その内容が以前のPreimageと100%一致する場合、即座に保存されたPostimageを適用します。Gitが何を記憶しているかは、以下のコマンドで確認できます:

bash\ngit rerere status

また、現在の修正内容と過去の記録との差異を確認することも可能です:

bash\ngit rerere diff

キャッシュ管理と高度なオプション

デフォルトでは、Rerereは修正内容を反映するだけで、自動的にgit addまでは行いません。これはユーザーが最終確認できるようにするためです。もしGitを完全に信頼し、ステージングまで自動化したい場合は、以下のオプションを有効にします:

bash\ngit config --global rerere.autoupdate true

ストレージのクリーンアップ

Rerereのデータはすべて.git/rr-cacheに保存されます。このディレクトリが肥大化するのを防ぐため、Gitは未解決のPreimageを15日後、解決済みの記録を60日後に自動的に削除します。手動でクリーンアップを行いたい場合は、以下のコマンドを使用します:

bash\ngit rerere gc

間違えて記録してしまった場合

誤った方法でコンフリクトを解消し、Gitがそれを記憶してしまったとしても心配いりません。以下のコマンドを実行することで、特定のファイルの学習内容をリセットできます:

bash\ngit rerere forget [ファイル名]

現場でRerereを使いこなすためのアドバイス

非常に便利な機能ですが、いくつか注意点があります。まず、Gitが自動解決を完了したと報告しても、必ず一度はファイルに目を通してください。周囲のロジック変更により、以前の解消方法が業務ロジックとして100%正しくない場合があるからです。次に、Rerereは設定ファイル、ボイラープレート、定数定義ファイル(constants)などで最大の効果を発揮します。

まとめると、Git Rerereは優秀な記録アシスタントのような存在です。あなたの思考を代行するわけではありませんが、無意味な繰り返しの手作業を排除してくれます。今日から有効にして、これまで手動コンフリクト解消に費やしてきた膨大な時間を賢く節約しましょう!

Share: