コンフリクトの解決を記録して再適用する git rerere

  • 51
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

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 ディレクトリが存在していれば有効になります。

(なお、.gitconfig に設定を入れても効かないようです・・・)

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 処理中、差分を表示します。
この投稿は Git Advent Calendar 201414日目の記事です。