はじめに
Git を使う場合、ブランチの作成とマージを頻繁に行うような運用が多いと思います。例えば、機能追加やバグ修正を行う場合には本流ブランチからトピックブランチを作成して、作業はトピックブランチにコミット、作業が終わったらトピックブランチを本流ブランチにマージ、といった運用です。
この場合、トピックブランチは細かい単位で作成して、作業が終わったらすぐマージする、というのが良いプラクティスであろうと思います。すぐマージすると、コンフリクトは起こらない場合が多いです。とはいえ、やはりコンフリクトが起こる場合はあります。
コンフリクトが起こる場合とは、feature/12345
ブランチを作成して作業して master
ブランチにマージしようとしたところ、別の誰かによる変更が既に master
ブランチに取り込まれており、しかもその変更箇所が feature/12345
ブランチでの変更箇所と重なっている、といった場合です。個人的には、何らかの IDE のプロジェクトファイルを共有している場合に、プロジェクトファイルの変更はコンフリクトしやすいと思います。
マージでコンフリクトが起こった場合は、それを解決します。どのように解決するかは、コミットしたい人が実際にコンフリクトしている部分を見て判断するしかないので、少々面倒な作業です・・・。それでも、大抵は一度だけの作業で、同じコンフリクトに何度も出会うことはなさそうです。
ところが、マージして git push
する前に、feature/12345
ブランチの内容の間違いに気づいてマージ作業をいったん取り消したとしましょう。そして、修正後に再びマージしようとして、同様のコンフリクトに遭遇・・・。一度だけのはずの作業をもう一度する羽目に・・・。
面倒ですよね。そこで登場するのが git rerere
です。
git rerere とは
Git には、git rerere という仕組みがあります。
これは、コンフリクトを解決してコミットした際に、どのように解決したかを自動的に記録してくれます。そして、同様のコンフリクトが発生した場合に、自動的に同じ解決を適用してくれます。
この機能は、マージやリベースのコンフリクトに対して働きます。
なお、rerere は "Reuse recorded resolution of conflicted merges" の略です。
使い方
事前設定
デフォルトでは無効になっています。使いたいリポジトリで以下を実行すると有効になります。
git config rerere.enabled true
または、.git
ディレクトリ以下に rr-cache
ディレクトリが存在していれば有効になります。
また、以下を実行するとすべてのリポジトリで有効になります(Pro Git Book : 7-9 Rerere)。
git config --global rerere.enabled true
rerere の発動
設定が有効になっていれば、通常の Git 操作のタイミングで自動的に rerere の機能が発動します。
git merge
でコンフリクトが発生した場合には、以下のように出力されます。"Recorded preimage for ..." のメッセージが出ています。
% git merge hoge
Auto-merging hoge.txt
CONFLICT (content): Merge conflict in hoge.txt
Recorded preimage for 'hoge.txt'
Automatic merge failed; fix conflicts and then commit the result.
コンフリクトを解決して git commit
すると、以下のように出力されます。"Recorded resolution for ..." のメッセージが出ています。ここで、どのように解決したかを自動的に記録しています。
% git commit
Recorded resolution for 'hoge.txt'.
その後、git merge
で同様のコンフリクトが発生した場合には、以下のように出力されます。"Resolved ... using previous resolution." のメッセージが出ています。ここで、自動的に同じ解決を適用しています。
% git merge hoge
Auto-merging hoge.txt
CONFLICT (content): Merge conflict in hoge.txt
Resolved 'hoge.txt' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
この時点ではコミットまではされません。内容に問題がなければ git commit
を行えばマージ完了です。
上記では git merge
の場合を例に挙げましたが、git rebase
の場合も同じように働きます。
git rerere コマンド
git rerere
というコマンドもあるのですが、このコマンドを直接使うことはほとんどありません。一応、ざっとサブコマンドを挙げておきます。
-
git rerere forget <pathspec>
: 指定した記録を削除します。 -
git rerere gc
: 古い記録を削除します。 -
git rerere clear
: rerere 処理が中断してしまったときに残るメタデータを削除します。 -
git rerere status
: rerere 処理中、記録しようとしているファイルパスを表示します。 -
git rerere remaining
: rerere 処理中、記録されないファイルパスを表示します。 -
git rerere diff
: rerere 処理中、差分を表示します。