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 feature for finding which commit introduced a bug by testing commits in a binary-search pattern.
CI
Continuous integration, an automated process that runs tests and checks when code changes are made.
Jujutsu
A version control tool, often abbreviated as jj, that works with Git repositories but offers a different model for editing and tracking changes.
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 commit history so changes can be moved or replayed onto a different base commit.
rerere
Short for reuse recorded resolution, a Git feature that remembers how you resolved a conflict and can apply that resolution again later.
worktree
A Git feature that lets you check out multiple working copies of the same repository 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