Merge vs Rebase: What Git Is Really Doing
A clear explainer of git merge versus git rebase — how each one rewrites or preserves history, what tradeoffs you accept, and the one rule you must never break.
Both git merge and git rebase exist to do the same job — integrate changes from one branch into another. They produce different histories because they go about it in fundamentally different ways, and understanding that difference is what stops you from corrupting a shared branch.
What merge actually does
A merge takes the work from two branches and joins them with a single new commit — the merge commit. That commit is unusual because it has two parents: the tip of the branch you were on, and the tip of the branch you pulled in. Every commit on both branches stays exactly where it was, untouched. Git just adds one node on top that says “these two lines of history came together here.”
Suppose you branched feature off main, and while you worked, someone else pushed commits to main. When you run git merge main from your feature branch, Git finds the common ancestor of the two branches, computes the changes on each side since then, combines them, and records the result as the merge commit.
main: A---B---C---D \ \feature: E---F---M ← M is the merge commit (parents: F and D)The payoff is that your history is true. You can see that E and F happened on a side branch, in parallel with C and D, and were joined at M. Nothing is invented or rewritten. The cost is that the graph gets bushy — a busy repo with many merges produces a tangled web that can be hard to read in a log.
What rebase actually does
A rebase does not join histories. It moves them. When you run git rebase main from your feature branch, Git takes each of your commits, sets them aside, fast-forwards your branch to the tip of main, and then replays your commits one at a time on top.
main: A---B---C---D \feature: E'---F' ← replayed copies of E and FNotice E' and F', not E and F. They are new commits. A commit’s hash is derived from its content plus its parent, and rebasing gives each commit a new parent — so every replayed commit gets a brand-new hash. The original E and F still exist for a while in Git’s internals, but your branch no longer points at them. The result is a straight line, as if you had branched from the current tip of main all along. No merge commit, no fork in the graph — just a clean, linear story.
That linearity is the whole appeal. git log reads top to bottom like a changelog, git bisect walks a simple sequence, and reviewers see your work as a tidy series of steps rather than a snapshot of parallel chaos.
The tradeoff, and the one rule
The core difference is this: merge is non-destructive and preserves context; rebase is destructive and rewrites it. Merge keeps the real, sometimes-messy shape of how work happened. Rebase manufactures a cleaner shape by discarding the old commits and creating new ones in their place.
Neither is “correct.” A common workflow is to rebase your own local feature branch to tidy it up before sharing, then merge it into main so the integration point is explicit. The line you must not cross is rewriting history that other people already have.
A useful mental shortcut: rebase is for cleaning up your own work before anyone sees it; merge is for combining work that is already public. If you remember only one thing, remember that rebasing public history breaks collaborators.
FAQ
FAQ
Does merge or rebase change my actual code?+
Why do my commit hashes change after a rebase?+
I accidentally rebased a shared branch — can I recover?+
Related reading
2026-06-04
ACID vs BASE: What Database Guarantees Actually Promise
ACID and BASE describe two ends of a tradeoff between strict correctness and scalable availability. Learn what each guarantee means, when each fits, and why most modern databases sit somewhere in between.
2026-06-04
Big-Endian vs Little-Endian
Byte order explained: how big-endian and little-endian lay out multi-byte numbers in memory, why network protocols pick one, and when the difference actually bites you.
2026-06-04
Big-O Notation in Plain English
Big-O describes how an algorithm's runtime or memory grows as input grows. Learn the common classes — O(1), O(log n), O(n), O(n log n), O(n^2), O(2^n) — with plain examples.
2026-06-04
CORS in Plain English: Why the Browser Blocks Your Fetch
A clear walkthrough of CORS and the same-origin policy — what an origin is, why your fetch fails, how servers opt in, and the big misconception about who CORS actually protects.
2026-06-04
Environment Variables and PATH, Explained
What environment variables actually are, why they hold config and secrets, and how PATH decides which binary runs when you type a command.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.