HN Debrief

Using Git's rerere feature to escape recurring conflict hell

  • Developer Tools
  • Programming
  • Open Source

The post is a short guide to Git’s `rerere` feature, short for “reuse recorded resolution.” Once enabled, Git stores how you fixed a particular merge conflict and can auto-apply the same fix when that exact conflict shows up again. The appeal is obvious if you keep resolving the same ugly hunk across repeated rebases, cherry-picks, or branch syncs.

If your team does repeated cherry-picks, long-lived branches, or stacked rebases, turn on `rerere` and `zdiff3` now. If you mostly do short-lived feature branches rebased onto `main`, the bigger win is tightening workflow rules and safer push habits rather than expecting `rerere` to save you often.

Discussion mood

Mostly positive on `rerere` as a useful sharp tool, but not as a universal fix. The mood was pragmatic and slightly weary with Git itself. People liked small config upgrades and safer defaults, yet kept coming back to the same conclusion: repeated conflicts usually reflect workflow and branch topology problems, not just missing commands.

Key insights

  1. 01

    Where rerere actually earns its keep

    It shines in branch-heavy environments where the same fix must be replayed across many similar lines of development. Think hardware variants, release branches, or long-lived dev branches with constant cherry-picks. In that world, `rerere` stops being a neat trick and becomes a way to survive the operational cost of duplicated history. The comments also make the deeper point that this pain comes from maintaining many divergent branches in the first place, which is why some teams prefer compile-time flags or other single-trunk mechanisms over branch-per-product sprawl.

    If you maintain multiple release or product branches, enable `rerere` before the next backport cycle. Then look hard at whether branch proliferation is masking a product-structure problem that should move into build flags, modularization, or release engineering instead.

      Attribution:
    • kazinator #1 #2
    • chuckadams #1
    • Sohcahtoa82 #1
  2. 02

    zdiff3 makes conflicts easier to resolve

    `merge.conflictStyle=zdiff3` got called out as a low-effort upgrade because it includes the original shared text in conflict markers and trims lines that already match. That gives you more context right where you are editing. It makes conflict resolution less guessy, which also improves the chances that your recorded `rerere` resolution is correct and reusable.

    Add `merge.conflictStyle=zdiff3` alongside `rerere`. Better conflict markers reduce bad manual resolutions, which is the failure you really want to avoid.

      Attribution:
    • 0123456789ABCDE #1
  3. 03

    You can train rerere from old merges

    Git already ships a `rerere-train` script that can populate the resolution cache from merges you have done in the past. That matters if you need to bisect or replay a large branch history after a bad merge and do not want to pay the conflict tax again from scratch. It turns `rerere` from a purely future-facing feature into something you can bootstrap when the repository is already in trouble.

    If a large branch or merge train has already happened, do not assume you missed your chance to benefit from `rerere`. Train it from existing history before a bisect, replay, or recovery effort.

      Attribution:
    • barchar #1
  4. 04

    Jujutsu fixes the part of conflict resolution Git makes painful

    The praise for Jujutsu was not generic tool hype. The specific win is that it treats conflict resolution more like normal editable state and less like a fragile all-or-nothing rebase session that can be derailed by interruptions. That directly targets the class of pain this post is about. The claim was that Jujutsu tolerates messy team workflows better than raw Git, even when the rest of the team stays on Git underneath.

    If your team regularly ends up in stacked rebases, interrupted conflict sessions, or history rewrites, test Jujutsu on one painful repo. It may reduce workflow friction more than another round of Git aliases and config tweaks.

      Attribution:
    • saghm #1
    • nchmy #1
    • mamcx #1

Against the grain

  1. 01

    Rebase-heavy workflows can trash commit history

    Frequent rebasing makes intermediate commits less trustworthy because nobody is rebuilding each rewritten step, and the resulting history often stops reflecting how the work actually evolved. From that view, polishing every commit is wasted effort. The only commit that really matters is the current tip. Merge commits do a better job preserving usable structure for integration, even if the history looks messier.

    Do not default to rebasing just because clean history sounds virtuous. If your team depends on bisectable intermediate commits or accurate integration history, prefer merges and reserve rebase for local cleanup.

      Attribution:
    • jstimpfle #1
  2. 02

    pull.rebase can surprise people badly

    Setting `pull.rebase=true` globally was challenged as a footgun for developers who do not fully understand what `git pull` will rewrite. The complaint was not theoretical. One workplace had support staff preinstall the setting and developers ended up in confusing rebases when they thought they were simply updating local state before resolving conflicts. The point is that hidden defaults are dangerous when they change history semantics.

    Do not roll out `pull.rebase=true` as a blanket team default unless everyone understands rebase mechanics. Prefer explicit commands or stronger guardrails if Git skill levels vary.

      Attribution:
    • Izkata #1 #2 #3
  3. 03

    Integration branches are sometimes the practical answer

    The push for strict one-way flow breaks down on large cross-cutting refactors, foundational API changes, and release-driven environments where testing is expensive. In those cases, forcing everything through `main` can just move the pain downstream and make one team eat a massive merge later. Integration branches let related work settle together before it hits the trunk. That is not elegant, but it can be cheaper than repeated rework on fast-moving `main`.

    If several teams are changing the same foundations, create a deliberate integration branch instead of pretending independent feature branches will stay independent. Treat it as temporary infrastructure with a clear merge plan, not a new permanent branch line.

      Attribution:
    • convolvatron #1 #2

In plain english

--force-with-lease
A safer form of Git force push that refuses to overwrite remote commits if the remote branch has changed since you last fetched it.
bisect
A Git debugging technique that searches commit history by repeatedly testing older revisions to find which commit introduced a bug.
CI
Continuous Integration, automated systems that build and test code changes before or after they are merged.
Jujutsu
A version control system and command-line tool, often abbreviated as jj, designed as an alternative interface around Git concepts.
pull.rebase
A Git configuration setting that makes `git pull` use rebase instead of merge when bringing in remote changes.
rebase
A Git operation that rewrites commits so they appear on top of a different base commit, often used to update a feature branch onto the latest main branch.
rerere
A Git feature whose name means “reuse recorded resolution,” which lets Git remember how you fixed a conflict and reapply that fix when the same conflict happens again.
Worktree
A Git feature that lets you check out multiple branches of the same repository into separate working directories at once.
zdiff3
A Git conflict marker style that shows both sides of a conflict plus the original shared base text to make manual resolution easier.

Reference links

Git docs and recovery references

Workflow articles and examples