Automating repeated conflict resolution with rerere Jump to heading

A long-lived branch rebased onto a fast-moving trunk hits the same conflict repeatedly: once per replayed commit during the rebase, again the next day after another git pull --rebase, and a third time when a colleague rebases the same branch. Resolving an identical conflict by hand each time is wasted effort and — worse — an invitation to resolve it inconsistently. Git’s rerere (“reuse recorded resolution”) subsystem records how you resolved a conflict and replays that resolution automatically the next time the same conflict appears. This page is a concrete recipe within Reusing Conflict Resolutions with rerere, which covers the mechanism and its place in a safe-merge toolkit.

When to use this approach Jump to heading

Turn on rerere when:

  • You rebase feature branches onto main frequently and keep re-resolving the same hunks, especially during multi-commit interactive rebases on shared branches.
  • A long-running integration branch merges from trunk on a schedule and the same structural conflict (a moved import, a renamed config key) recurs every cycle.
  • You use “rebase, test, discover a problem, git rebase --abort, retry” loops and want the second attempt to skip the conflicts you already solved.
  • Your team wants conflict resolutions to be consistent across engineers rather than each person guessing at the same merge.

This recipe is not the right fit if the “conflict” is really a semantic decision that should differ each time it appears — rerere assumes an identical textual conflict deserves an identical resolution, which is exactly the assumption that makes a silent wrong replay dangerous.

The diagram below shows the record-once, replay-many flow that rerere implements.

rerere record and replay flowFirst conflict is resolved by hand and recorded to the rr-cache keyed by a conflict hash. On every later identical conflict, rerere looks up the hash and replays the stored resolution, optionally staging it automatically.First conflictresolved by handrecord to rr-cachekey = conflict hashvalue = resolution.git/rr-cachestored on diskNext identical conflictrebase / merge replaylookup by hashauto-apply resolutionstaged if autoUpdate is on

Step-by-step recipe Jump to heading

Step 1 — Enable rerere and autoUpdate Jump to heading

rerere.enabled turns on recording and replay. rerere.autoUpdate additionally stages the replayed resolution so a rebase can continue without a manual git add. Set both globally so every repository benefits:

# Record and replay resolutions everywhere
git config --global rerere.enabled true
# Auto-stage a replayed resolution instead of leaving it unstaged
git config --global rerere.autoUpdate true

Verify both flags resolved to true:

# Each command should print: true
git config --get rerere.enabled
git config --get rerere.autoUpdate

Enabling rerere.enabled also creates the .git/rr-cache directory in each repo the first time a conflict is recorded — no manual setup is needed.

Step 2 — Resolve the conflict once during a rebase Jump to heading

Start the operation that produces the conflict. During a long rebase, Git stops at the first conflicting commit:

# Replay this feature branch onto the updated trunk
git rebase main
# Git halts: "CONFLICT (content): Merge conflict in src/config.ts"

The moment the conflict appears, rerere records the pre-image — the raw conflict, keyed by its hash. Resolve the file exactly as you intend it, then confirm and continue:

# Edit src/config.ts to the correct merged content, then:
git add src/config.ts
git rebase --continue

Verify the file no longer contains conflict markers before you stage it:

# Prints nothing when the file is fully resolved
grep -nE '^(<<<<<<<|=======|>>>>>>>)' src/config.ts

Step 3 — Confirm the resolution was recorded Jump to heading

rerere captured the post-image (your resolution) when you ran git add on the resolved file. Check that it is now stored:

# Lists conflict paths for which a resolution has been recorded
git rerere status

You can also see the recorded cache entry on disk. Each conflict hash gets its own directory holding preimage and postimage files:

# One subdirectory per recorded conflict hash
ls -1 .git/rr-cache/

If git rerere status prints the path you just resolved, the resolution is banked and ready to replay.

Step 4 — Watch the resolution auto-replay on the next conflict Jump to heading

The next time the identical conflict appears — a later commit in the same rebase, a re-run after git rebase --abort, or tomorrow’s git pull --rebasererere recognizes the hash and replays your resolution:

# Re-run the rebase after aborting, or pull again later
git rebase main
# Git reports: "Resolved 'src/config.ts' using previous resolution."

With rerere.autoUpdate on, the file is already staged. Confirm the replay actually produced the content you expect before continuing:

# Review what rerere staged — do NOT trust it blindly
git diff --cached src/config.ts
# If correct, continue the rebase
git rebase --continue

SAFETY WARNING: With rerere.autoUpdate enabled, a previously recorded wrong resolution is replayed and staged silently — Git prints one “using previous resolution” line and moves on, so a bad merge can slip into a commit unnoticed. Always run git diff --cached on the auto-resolved path before git rebase --continue, and if the replay is wrong, drop it with git rerere forget <path> and resolve by hand.

Step 5 — Share the rr-cache across the team Jump to heading

By default .git/rr-cache is local and never pushed. To let a whole team reuse the same resolutions for a recurring integration conflict, sync the cache directory out of band — a shared location plus a symlink is the simplest reliable pattern:

# One-time: move the cache to a shared, synced location and link it back
mkdir -p /shared/team-rr-cache
mv .git/rr-cache/* /shared/team-rr-cache/ 2>/dev/null || true
rm -rf .git/rr-cache
ln -s /shared/team-rr-cache .git/rr-cache

For teams without a shared filesystem, commit resolutions from a designated “integrator” and distribute the rr-cache entries as a tarball, or use a dedicated sync tool. Verify the link resolves and Git still reads it:

# Should show the symlink target and list shared hash directories
ls -ld .git/rr-cache && ls -1 .git/rr-cache/

Because every entry is keyed by a content hash, merging two caches never collides destructively — identical conflicts map to identical directories, and unrelated ones coexist.

Step 6 — Inspect state and forget a bad resolution Jump to heading

Two commands give you visibility into what rerere is holding. git rerere status lists paths with an active recorded resolution during a conflict; git rerere diff shows the difference between the recorded conflict and its stored resolution:

# Which conflicted paths have a recorded resolution?
git rerere status
# What resolution will be applied for the current conflict?
git rerere diff

When a resolution is wrong — or you resolved a conflict incorrectly and it is now poisoning every replay — remove it so the conflict resurfaces for a clean redo:

# Drop the recorded resolution for this path; the conflict returns
git rerere forget src/config.ts

Verify the entry is gone and then re-resolve the conflict correctly, which records a fresh resolution:

# The path should no longer appear as auto-resolved
git rerere status
# Re-edit the file, then re-stage to record the corrected resolution
git add src/config.ts

SAFETY WARNING: git rerere forget <path> only drops the recorded resolution — it does not revert any commit that already captured the bad merge. If a wrong auto-replay was already committed during a rebase, fix history separately (for example with an interactive rebase on the shared branch) after forgetting the cache entry.

Validation checklist Jump to heading

Before relying on rerere for real conflict work, confirm each item:

Frequently asked questions Jump to heading

Does rerere change my commits or only my working tree? Jump to heading

rerere only stages resolved file contents in your working tree and index; it never creates or amends commits on its own. With rerere.autoUpdate on, it applies the recorded resolution and stages the file, but you still complete the merge or rebase step yourself with git rebase --continue or git commit. Without autoUpdate, it writes the resolution into the working file but leaves it unstaged so you can review before running git add.

How does rerere decide two conflicts are the same? Jump to heading

rerere computes a normalized hash of the conflict itself — the pre-image formed by the conflicting hunks and their surrounding context, with branch-specific noise stripped out. The recorded resolution is keyed by that hash under .git/rr-cache. If the same conflict shape reappears, even in a different file path or a later rebase replay, the hashes match and the stored resolution is reused. This is also why a resolution recorded on one machine can be shared: the key is derived purely from conflict content.

Can rerere apply a wrong resolution without telling me? Jump to heading

Yes. If a conflict hashes identically to one you previously resolved incorrectly, rerere replays the bad resolution and — with autoUpdate — stages it silently, printing only a one-line “using previous resolution” notice. Always review the auto-resolved diff with git diff --cached before continuing, and run git rerere forget <path> to drop the recorded resolution so the next occurrence conflicts normally and you can redo it correctly.