Back to blog
Feb 2026·4 min readAI-generated

Git Rebase vs Merge: When to Use Which

#git#workflow

git merge and git rebase both get your feature branch's changes onto main, and that surface-level similarity is exactly why people mix them up and end up with either a tangled history or a rewritten one they didn't mean to rewrite. They solve the same problem in fundamentally different ways, and picking the wrong one for the situation is how you get force-push disasters or unreadable commit graphs.

What each one actually does

Say main has moved on since you branched, and your feature branch has its own commits:

      A---B---C  feature
     /
D---E---F---G  main

Merge creates a new commit that ties the two histories together, with two parents:

git checkout feature
git merge main
      A---B---C-------H  feature
     /               /
D---E---F---G--------  main

Nothing about A, B, or C changes. H is a new merge commit recording "these two lines of history are now joined." The full history — including the fact that you branched off before F and G landed — stays intact.

Rebase takes your commits and replays them, one by one, on top of the new base:

git checkout feature
git rebase main
D---E---F---G---A'---B'---C'  feature

A', B', C' are new commits — same changes, same messages, but different parent, which means different commit hashes. The branch point where you diverged is gone; it now looks like you branched off G and wrote your three commits from there, in a straight line.

Why this distinction matters

The core trade-off: merge preserves what actually happened, rebase produces a cleaner-looking history that didn't literally happen that way. Both are useful — for different audiences.

  • Merge is honest about the parallel work. If two people were both building on an old main and their branches diverged and reconverged, a merge commit records that truthfully. It's non-destructive — no existing commit is altered, so it's always safe on shared branches.
  • Rebase makes the history read as if it happened serially, which is easier to follow later — git log shows one clean line instead of a lattice of merge commits — but it rewrites commit hashes, which is where the danger comes in.

The rule that actually matters: never rebase shared history

git checkout feature
git rebase main
git push --force-with-lease

If feature is a branch only you are working on, this is fine — you're rewriting commits nobody else has based work on. If feature (or worse, main) is a branch other people have already pulled and built on top of, rebasing it rewrites history out from under them: their local branch's history and the remote's diverge, and their next pull produces a confusing tangle of duplicate commits, or their local commits appear to vanish (they haven't — they're just no longer reachable from the branch they thought they were following).

The rule of thumb: rebase freely on branches only you push to, merge (or use a rebase-and-fast-forward via a PR tool) for anything already shared.

Interactive rebase: cleaning up before you share

The other common use of rebase isn't about a different base at all — it's cleaning up your own unpushed commits before opening a PR.

git rebase -i HEAD~4

This opens an editor listing your last four commits, letting you reorder them, squash "fix typo" and "actually fix typo" into the commit they belong to, or reword messages — all before anyone else has seen them. This is the safest, most common use of rebase in practice: turning a messy work-in-progress history into a small number of coherent commits, before it becomes shared history.

Merge conflicts feel different in each

With a merge, you resolve conflicts once, in the single merge commit. With a rebase, if multiple commits touch the same lines, you can hit the same conflict repeatedly — once per commit being replayed — which is more tedious but also more precise: you're resolving each historical change in the context it was actually made, not one giant diff at the end.

git rebase main
# CONFLICT in commit B
# ...resolve...
git add .
git rebase --continue
# CONFLICT in commit C, same lines
# ...resolve again...
git add .
git rebase --continue

If a rebase turns into a repeated-conflict slog, git rebase --abort gets you back to exactly where you started — worth remembering before you're three conflicts deep and unsure if you're making it worse.

A practical default

  • Working on your own feature branch, want to catch up with main before continuing: rebase.
  • Cleaning up commits before opening a PR: rebase -i.
  • Bringing a finished, reviewed feature branch into main: whichever your team's convention is — both are defensible, and consistency matters more than the choice.
  • Anything already pushed and possibly pulled by someone else: merge, or rebase only with explicit team agreement and a heads-up.

Takeaway

Merge tells the truth about parallel history at the cost of a more tangled graph; rebase produces a clean linear graph at the cost of rewriting commit identity. The line that actually matters isn't "which is better" — it's whether the commits you're about to rewrite are still only yours.

NewerThe N+1 Query Problem and How to Avoid ItOlderWriting Safe, Idempotent Database Migrations