前回のDay 30では、全リポジトリのコミット差分から消えた過去の関数や定数を0.1秒で掘り当てる「git log -S(つるはし検索)」の神技を学びました。
そして本日のDay 31は、チーム開発や長期ブランチ運用において全エンジニアが一度は激しいストレスを感じるあの悩み——
「毎朝 main をリベース(マージ)するたび、昨日と全く同じコンフリクトを何度も手作業で解かされる……!」
という無駄な作業をこの世から完全に消滅させる奇跡の魔法——
【git rerere で過去に解決したコンフリクトを全自動解決させる魔法】を徹底解説します!
rerere とは、「Reuse Recorded Resolution(記録された解決の再利用)」の略称です。
この機能を有効にしておくだけで、Gitはあなたが一度手動で解いたコンフリクトの「衝突パターン」と「解決結果」を裏側で自動記憶します。
そして次回以降、全く同じコードの衝突が発生した瞬間に、人間が何もしなくてもGitが全自動でマージを完了してくれるのです!
C#ソリューションでのNuGet依存関係の競合や共通設定ファイルの衝突など、現場の消耗を一掃するプロの必須テクニックを身につけましょう!
① 導入・本日の達成目標
複数人で開発を進めていると、数週間〜数ヶ月に及ぶ長期フィーチャーブランチを運用することがあります。
最新の main ブランチの変更を取り込もうと git rebase main や git merge main を行うたびに、まったく同じファイルの同じ行でコンフリクトが発生し、何度も同じ解消作業を繰り返した経験はないでしょうか?
これは開発者の集中力を削ぎ、誤ったマージによるバグ混入のリスクを高める重大な原因です。
Gitに備わっている git rerere を活用すれば、過去の解決結果が自動適用され、コンフリクト解決の苦痛から完全に解放されます。
git rerere(Reuse Recorded Resolution)の基本概念と絶大な自動化メリットを理解する- 手動解決の繰り返しによる人的ミスやストレスがなぜ発生するのか、その構造的課題を把握する
git rerereの動作フロー(記録開始 → 初回手動解決 → 自動解決適用)の3ステップを完全習得するgit config --global rerere.enabled trueによる環境設定と.git/rr-cache/の内部構造を理解する- C#プロジェクト(.csprojのNuGet更新や共通ヘッダー)における実践的なコンフリクト自動解決ノウハウを体得する
② 【図解】何度も同じ競合を手動解決する苦痛 vs git rerereの自動解決
まずは、従来の開発フローと git rerere を導入した後の世界の違いを図解で見てみましょう。
SVNや従来のGit運用では、ブランチを長期間分岐させたまま何度も同期をとる際、同じ衝突を毎回手作業でエディタを開いて解消する必要がありました。
| 比較項目 | 従来のコンフリクト対応 | git rerere 有効時の対応 |
|---|---|---|
| リベース/マージの反復 | 同じ衝突が起きるたびに処理がストップし、手作業で解消してコミットが必要。 | 過去の解消パターンと一致した瞬間、Gitが0秒で自動解消してそのまま進行。 |
| 人的ミスのリスク | 高(疲労や急ぎの作業で、必要なコードを誤って消去してしまう事故が発生)。 | 極小(一度検証された正しい解決手順が100%正確に再現される)。 |
| 複数ブランチでの流用 | 他の派生ブランチで同じマージを行う際、別の開発者が再度同じ悩みを抱える。 | 同一リポジトリ内であれば、別のブランチのリベースでも自動適用可能。 |
③ 【図解】git rerere 動作の3ステップ(記録・検知・自動適用)
git rerere がどのようにして競合を記憶し、自動解決を適用するのか、その3ステップの動作フローを確認しましょう。
ステップ①【競合検知・事前状態の自動記録】
git merge や git rebase でコンフリクトが発生した瞬間、Gitはターミナルに以下のようなメッセージを出力します:
$ git merge main
Auto-merging Services/OrderService.cs
CONFLICT (content): Merge conflict in Services/OrderService.cs
Recorded preimage for 'Services/OrderService.cs'
Automatic merge failed; fix conflicts and then commit the result.
ここで表示された Recorded preimage for 'Services/OrderService.cs' という行に注目してください!
これが「コンフリクト前の衝突形状(Preimage)をGitがキャッシュに記録した」合図です。
ステップ②【初回のみ人間が手動解決してコミット】
初回の1回だけは、開発者が通常通りエディタ(VS CodeやVisual Studio)で競合マーカー(<<<<<<< / ======= / >>>>>>>)を解消します。
解消後、ファイルをステージングしてコミット(または git rebase --continue)します。
$ git add Services/OrderService.cs
$ git commit -m "Merge main and resolve conflict in OrderService"
Recorded resolution for 'Services/OrderService.cs'.
コミット時に Recorded resolution for 'Services/OrderService.cs'. と表示され、Gitは「この競合パターンに対して、人間がどのように解決したか(Postimage)」を学習・保存しました!
ステップ③【次回以降、同一競合をGitが全自動適用】
将来、別のブランチのテストマージを破棄してやり直した際や、トピックブランチのリベース中に再び同じコミットが衝突した際、Gitは以下のように応答します:
$ git rebase main
Auto-merging Services/OrderService.cs
CONFLICT (content): Merge conflict in Services/OrderService.cs
Resolved 'Services/OrderService.cs' using previous resolution.
なんと!Resolved 'Services/OrderService.cs' using previous resolution. と表示され、前回の解決策が自動適用されてファイルが既に綺麗に解決済みの状態になっています!
開発者はエディタで競合を手直しする必要すらなく、そのまま git add して次へ進むことができます。
④ 【図解】rerereの有効化とキャッシュ(.git/rr-cache)の仕組み
git rerere は標準のGitに最初から組み込まれていますが、デフォルトでは無効(オフ)になっています。まずは一発で有効化しましょう。
rerere をグローバルに有効化するコマンド
開発マシンのターミナル(PowerShell等)で以下のコマンドを実行するだけで、全リポジトリで自動記録が有効化されます。
# 全リポジトリで rerere を有効化(推奨)
$ git config --global rerere.enabled true
# (オプション)自動解決されたファイルを自動で git add まで行わせる場合
$ git config --global rerere.autoupdate true
rerere.autoupdate true を設定すると、Gitが過去の解決結果を適用したファイルを自動的にステージング(git add)してくれます。
初心者のうちは「自動解決された結果を目視で確認してからステージングしたい」ことが多いため、まずは rerere.enabled true だけを設定するのが安全でおすすめです。
内部構造: .git/rr-cache ディレクトリ
Gitは衝突の差分ブロックからSHA-1ハッシュ(フィンガープリント)を計算し、.git/rr-cache/<ハッシュ>/ ディレクトリ内に以下の2つのファイルを保持します:
preimage: 競合発生時の両ブランチの差分テキスト(衝突パターン)postimage: 人間が手動で正しく解決したあとの完成形テキスト
不要になった古いキャッシュは、git rerere gc コマンドで安全に定期クリーンアップ(デフォルトで未解決は15日、解決済みは60日)されるため、リポジトリが肥大化する心配もありません。
⑤ 【図解】C#現場での git rerere 実践術
実際の.NET / C# 開発現場で、git rerere がどれほどの威力を発揮するのか、頻出シナリオを見ていきましょう。
シナリオ①: 長期フィーチャー開発での「使い捨てテストマージ」
機能開発に数週間かかる場合、「現時点で main とマージしたら動くかどうか確認したい」という理由で、ローカルで一時的に main をマージして動作確認(ビルド・単体テスト)することがあります。
動作確認が終わったら、履歴を汚さないために git reset --hard HEAD~1 でマージを取り消します。
もし rerere が無ければ、後日本当にプルリクエストをマージする際に、また同じコンフリクトを一から手動解決しなければなりません。
しかし git rerere が有効なら、テストマージ時に解いた解決策がしっかり記憶されているため、本番マージの際は一瞬で自動解決されます!
シナリオ②: .csproj(NuGetパッケージ更新)での頻発コンフリクト
C#プロジェクトファイル(.csproj)は、複数人が同時にパッケージを追加・バージョンアップした際にコンフリクトが起きやすい典型例です。
<!-- 衝突例: MyApp.csproj -->
<<<<<<< HEAD
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
=======
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
>>>>>>> main
両方のパッケージを綺麗に統合した結果を一度コミットしておけば、フィーチャーブランチ側で何度リベースをやり直しても、.csprojの競合で立ち止まることは二度となくなります!
自動解決された内容が意図通りか確認したい場合は、コミット前に git diff を叩くだけです:
$ git diff
また、git rerere status で現在どのファイルが自動解決対象として処理されたか一覧表示できます。もし手違いで誤った解決を記録してしまった場合は、git rerere clear や git rerere forget <file> で安全にキャッシュを忘却させることが可能です!
⑥ まとめ&次回予告
📌 本日の最重要ポイントまとめ
- git rerere は「コンフリクト解決の自動再生機」: Reuse Recorded Resolutionの略で、一度解いた衝突パターンをGitが学習・自動適用!
- 有効化は1コマンド:
git config --global rerere.enabled trueを打つだけで今すぐ全リポジトリで稼働開始。 - 動作の3ステップ: ①衝突時に
Recorded preimage→ ②初回手動コミットでRecorded resolution→ ③次回以降Resolved using previous resolutionで0秒自動解決。 - テストマージとリベースの強力な味方: 破棄前提の事前結合テストや日々のリベースで、同じ競合を何度も解く苦痛をゼロ化。
- 誤解決も安全に取り消し可能:
git rerere forget <file>で特定のキャッシュを消去して再学習させられる安心設計。
🚀 次回予告【Day 32】
次回は、ターミナルでの日々のGit操作スピードを爆発的に高める効率化テクニック——
【git switch - やエイリアス設定で日常操作を10倍爆速化する】をお届けします!
直前のブランチへ一瞬で戻る switch - の使い方や、タイピング数を半減させるプロ厳選の git config alias、PowerShellでのGitブランチ可視化(posh-git)まで、エンジニアの手元を異次元に加速させる時短テクニックを大公開します。お楽しみに!
コメント
コメントを投稿