Sharing rerere resolutions across a team Jump to heading
When a long-lived branch is rebased onto a fast-moving trunk, several people hit the same conflict in the same week and each resolves it independently β sometimes differently, which is worse than the wasted effort. Gitβs recorded-resolution cache solves this per machine; sharing it solves it per team. The cache is also, viewed less charitably, a mechanism for applying one personβs judgement to other peopleβs merges without asking, which is why this recipe is as much about review as about copying files. It extends Reusing Conflict Resolutions with rerere.
When to use this approach Jump to heading
- Several engineers rebase the same long-lived branch and hit identical conflicts.
- A cross-cutting refactor on the trunk conflicts with every branch in flight in the same way.
- One person has already worked out the correct resolution and it is genuinely mechanical.
- Consistency matters: the same conflict resolved two ways produces a subtle behavioural difference.
- If the conflict requires judgement that could reasonably differ per branch, do not share it. Let each person see the conflict.
Step 1 β Inspect what your rr-cache actually contains Jump to heading
# rerere must be recording in the first place
git config rerere.enabled true
git config rerere.autoUpdate true
# What has been recorded? Each directory is one conflict signature.
ls .git/rr-cache/
git rerere status # conflicts recorded for the current operation # Read a specific resolution before you consider sharing it
for d in .git/rr-cache/*/; do
echo "=== $d"
[ -f "$d/preimage" ] && head -20 "$d/preimage"
[ -f "$d/postimage" ] && echo "--- resolved to:" && head -20 "$d/postimage"
done What changed: nothing β but you can now see that a cache entry is a pair of files, the conflicted text and what you turned it into, keyed by a hash of the conflict.
Step 2 β Export only the resolutions worth sharing Jump to heading
Do not share the whole cache. It contains every conflict you have ever resolved, including ones specific to your own half-finished experiments.
# Identify the entry for a conflict you want to share, by its content
grep -rl 'settlementJournal' .git/rr-cache/*/preimage
# Export just that entry, with a README explaining the decision
mkdir -p /tmp/rr-share/4f2a9c1b8e7d6a5c4b3a2918
cp .git/rr-cache/4f2a9c1b8e7d6a5c4b3a2918/preimage \
.git/rr-cache/4f2a9c1b8e7d6a5c4b3a2918/postimage \
/tmp/rr-share/4f2a9c1b8e7d6a5c4b3a2918/
cat > /tmp/rr-share/README <<'EOF'
Conflict: LedgerβJournal rename versus the settlement export branch.
Resolution: keep the renamed symbol, retain the branch's added guard clause.
Decided by: r.okafor, reviewed in PR #2841.
Expires: after the export branch merges β the conflict stops existing.
EOF
tar -czf rr-settlement-rename.tgz -C /tmp/rr-share . What changed: a single, documented resolution is packaged for other people, with the reasoning that made it correct and a note about when it stops applying.
# Verify the archive holds only what you intended
tar -tzf rr-settlement-rename.tgz SAFETY WARNING β a postimage is arbitrary file content that will be written into a colleagueβs working tree and, with
rerere.autoUpdateon, staged automatically. Anyone who can hand you a cache entry can put code into your commit without it appearing as a conflict. Only import archives from people you would give commit access to, read the postimage before importing, and diff the result of the first merge that uses it.
Step 3 β Import into another clone Jump to heading
# Extract into the recipient's cache
mkdir -p .git/rr-cache
tar -xzf rr-settlement-rename.tgz -C .git/rr-cache
# Read what you just accepted β before it is applied to anything
cat .git/rr-cache/4f2a9c1b8e7d6a5c4b3a2918/postimage # Confirm it applies on the next occurrence
git rebase origin/main
# Expect: Resolved 'src/settlement/export.ts' using previous resolution.
# Then check what it did, rather than trusting it
git diff --cached src/settlement/export.ts That last diff is not optional. An automatically applied resolution is the only kind of merge outcome that reaches your index without you having looked at the conflict, and a shared resolution is one you did not even make.
Step 4 β Expire resolutions when the code moves on Jump to heading
A shared resolution is correct for a particular pair of changes. Once the branch merges or the code is rewritten, the entry is at best dead weight and at worst a resolution applied to a conflict that only superficially resembles the original.
# Drop a specific recorded resolution
git rerere forget src/settlement/export.ts
# Prune entries the cache has not matched recently
git config gc.rerereResolved 60 # days to keep resolved entries
git config gc.rerereUnresolved 15
git gc --prune=now # Confirm the entry is gone and the conflict returns to being manual
ls .git/rr-cache/ | wc -l
git rebase origin/main # the conflict now presents normally The expiry note in the exported README is what makes this happen. Without a stated end condition, a shared cache entry outlives the situation that justified it, and the day it silently resolves a conflict that needed thought is the day the whole practice becomes a liability.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Is sharing an rr-cache safe? Jump to heading
It is safe in the sense that it cannot corrupt a repository, and risky in the sense that it silently applies somebody elseβs judgement to your merge. A recorded resolution is a decision about what two conflicting changes should become β importing one means adopting that decision without seeing the conflict. Share deliberately, review what you import, and never automate the import into every clone.
Why not just commit the rr-cache to the repository? Jump to heading
Because it would then be applied automatically on every clone with no review step, which turns an opt-in convenience into a silent policy. It also accumulates: entries whose conflicts stopped existing years ago stay forever, and nothing prompts anyone to remove them. Distribute it as an artefact people choose to import instead.
How do I know a shared resolution was applied? Jump to heading
Git prints Resolved '<path>' using previous resolution during the merge or rebase, and the file is staged if autoUpdate is on. Read that line β it is the only notice you get that a decision was made for you. Diff the result before continuing, particularly for a resolution you imported rather than recorded yourself.
Related Jump to heading
- Reusing Conflict Resolutions with rerere β the parent guide: how conflicts are hashed and when a match is trustworthy.
- Automating Repeated Conflict Resolution with rerere β the single-machine workflow this recipe extends to a team.
- Keeping a Long-Lived Branch in Sync with Main β the situation that generates the repeated conflicts worth sharing.