Git rerere ♲
Fixing the same conflict over and over again is cumbersome process. Especially when Git is so nice that it offers a mechanism to spare you that chore, at least most of the time. Git rerere (Reuse Recorded Resolution) is a hidden git feature which, as the name says, allows record and reuse previous conflicts resolutions.
With rerere, when you first encounter a conflict, you resolve the conflict in some way, but you tell git to learn and remember how the conflict was resolved. Afterwards, if the same conflict occurs again, and rerere is enabled, git will resolve the conflict automatically the same way you did it before, reapplying previously recorded resolutions.
In order to use this command it needs be enabled
git config --global rerere.enabled true
Once you have set rerere.enabled
, when git does a merge — any merge, including those from git am
and git rebase
and git cherry-pick
and so on, not just those from git merge
itself—and hits a conflict, git will:
- record the conflicting diff hunks
- wait for you to resolve them manually
- record (at
git commit
time) what you did to resolve them
This process is done only the first time when you encounter conflict. If the conflict is encounter again in the future, there will be only one step which git will perform:
- check for previous recorded resolutions for these conflicts: if they exist, use them to resolve those conflicts automatically
If you followed carefully you have seen that there was no command entered to make rerere run. This is because rerere command is a little different git command which, once enabled, runs automatically without user interaction or arguments. However there are options that allow you to modify the state of remembered information and to understand what rerere knows.
git rerere [clear|forget <path>|diff|remaining|status|gc]
None of this commands record or reuse a resolution, they help you on the way of the conflict resolution
status
: does similar job asgit status
command, telling the user which files have conflicts that rerere will monitor and record the resolutiondiff
: does similar job asgit diff
command, displaying differences for the current state of the conflict resolutionremaining
: prints paths with conflicts that have not been autoresolved by rerereclear
: reset the metadata used by rerere if a merge resolution is to be abortedforget <pathspec>
: tells git to forget recorder resolutions for file specified with<pathspec>
gc
: prunes records of conflicted merges that occurred a long time ago
Practical application
Consider that you have long-lived feature
branch, created from develop
branch. Periodically you want to sync with develop
to stay up-to-date. With rerere enabled and conflicts resolved manually (for the first time), you are teaching git how to deal with any similar future conflicts, by reapplying resolution from recorder history. This results in fewer delays and less complications because git uses already learned conflict resolutions through temporary merges.
To go through the process let's say that we are working on feature
branch and after sometime we want to sync with develop
by doing merge:
$ git merge develop
Auto-merging HelloWorld.java
CONFLICT (content): Merge conflict in HelloWorld.java
Recorded preimage for 'HelloWorld.java'
Automatic merge failed; fix conflicts and then commit the result.
Git found out that there is a conflict, but as this is the first time it is encountered we need to resolve it manually. When the conflicts are resolved manually and changes are commited, git will record changes:
Recorded resolution for 'HelloWorld.java'.
If sometimes in the future you encounter similar conflict, git will autoresolve it using recorded resolution, and the output will show successful resolution:
Auto-merging HelloWorld.java
CONFLICT (content): Merge conflict in HelloWorld.java
Resolved 'HelloWorld.java' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
Key takeaways
- Rerere remembers how you chose to resolve the conflicted regions
- Rerere also remembers how you touched up outside the conflicted regions to adjust to semantic changes
- Rerere can reuse previous resolution even though you were merging two branches with different contents than the one you resolved earlier