Git Rebase vs Merge: When to Use Each
Understand git rebase versus merge: how rebase rewrites history for a clean line, when to prefer each, and the golden rule of never rebasing shared commits.

You've been on a feature branch for two days. main moved on without you. Three commits landed while you were heads-down. Now you need your work and theirs in the same place, and Git gives you two ways to do it: merge or rebase. They produce the same files. They produce very different history. Pick the wrong one on a shared branch and you'll make enemies. This lesson is about telling them apart and knowing which to reach for.
The setup: two branches that diverged
Say you branched off main at some commit, made two commits on feature, and meanwhile two more commits landed on main. Your history forked. To combine them you either merge (tie the two lines together with a new commit) or rebase (lift your commits off and replant them on top of the latest main).
Here's what a merge gives you, both lines preserved, joined by a merge commit:
See the fork and the join? Commit M is the merge commit. It has two parents and exists purely to say "these two histories came back together here." Nothing was rewritten. F1 and F2 are exactly the commits you wrote, in their original spot.
Now here's the same work after a rebase instead:
One straight line. No fork, no merge commit. Your two feature commits now sit on top of C and D as if you'd written them after main's latest work. Notice they're labelled F1' and F2', not F1 and F2. That prime mark matters, and we'll get to why.
What rebase actually does
A rebase replays your branch's commits on top of another branch. That's the whole idea in one sentence. Git takes each commit you made on feature, sets it aside, fast-forwards your branch to the tip of the target, then re-applies your commits one by one on the new base.
From your feature branch, you run:
git checkout feature
git rebase mainGit rewinds your commits, moves the branch base to the current tip of main, and reapplies F1 then F2 on top. If a commit touches the same lines as something that landed on main, you'll get a conflict to resolve right there. Fix it, git add the file, then git rebase --continue. (Stuck and want out? git rebase --abort puts everything back the way it was.)
The result is the clean linear history from the second diagram. When you later merge feature into main, Git can fast-forward, no merge commit needed, because there's nothing to reconcile. The line was already straight.
Why the commits get new hashes
A commit's hash is computed from its content and its parent. Rebasing gives each commit a new parent (the latest main instead of the old base), so every replayed commit gets a brand-new hash. F1 becomes F1', same changes, different identity. That's not cosmetic. It's the entire reason the golden rule below exists.
Merge vs rebase: the trade-off
Both end with your work combined with main. The difference is what the history says afterward.
Merge preserves history. It records exactly what happened: you branched here, worked in parallel, joined back there. The merge commit is a true fact about how the project evolved. The cost is that history becomes a braid. On a busy repo, git log turns into a tangle of crossing lines and dozens of "Merge branch 'main' into…" commits that carry no real information.
Rebase rewrites for a clean line. It throws away the "we worked in parallel" detail and pretends you wrote your commits after everyone else's. git log reads like a story, top to bottom, no noise. The cost is that it's a lie about the timeline, and, more seriously, it changes commit hashes, which is dangerous the moment those commits aren't yours alone anymore.
Quick check
What's the key difference between merge and rebase when combining a feature branch with main?
The golden rule
This is the one thing to carry out of this lesson, even if you forget everything else.
Never rebase commits you've already pushed or shared
Rebasing rewrites commit hashes. If you rebase commits that someone else has already pulled (or that live on a shared branch like main), their history and yours no longer agree on what those commits are. Git will demand a force-push, and anyone who based work on the old commits is now stranded with duplicates, broken merges, and a very confusing afternoon. Rebase only commits that exist only on your machine.
The safe test is simple: have these commits left your laptop? If they're only local (your private feature branch, not yet pushed, or pushed only to a personal branch nobody else touches), rebase freely. The moment commits are on a branch other people pull from, treat their hashes as permanent and use merge instead.
If you do rebase a branch you'd already pushed (sometimes legitimate on a personal feature branch mid-review), push with git push --force-with-lease rather than plain --force. --force-with-lease refuses to overwrite if someone else pushed in the meantime, which saves you from clobbering a teammate's work by accident.
Interactive rebase for tidying local commits
There's a second flavour worth one line: git rebase -i HEAD~5 opens an interactive rebase over your last five commits, letting you reorder, squash, edit messages, or drop commits before they go public. It's perfect for turning six messy "wip", "fix typo", "actually fix it" commits into two clean ones. Same golden rule applies: only do it on commits you haven't shared.
What I'd actually do
After years of watching teams argue about this in pull request comments, here's the policy that holds up:
- Rebase for local cleanup. Before I open a pull request, I rebase my feature branch onto the latest
mainand usegit rebase -ito squash my scratch commits into a tidy, reviewable set. The reviewer sees clean work, not my live-typing. - Merge for shared integration. When the feature actually lands in
main, I let it merge (often a squash-merge through the platform's "Merge" button). The shared branch's history stays append-only, so nobody's hashes ever get rewritten under them.
That combination gives you readable branches and a safe shared history. The one rule that overrides all of this: whatever your team's standard is, follow it. A consistent merge-everything repo beats a repo where half the people rebase and half don't. Decide as a team, write it down, move on.
The deeper mechanics (what --onto does, how to recover a botched rebase with git reflog) are laid out well in the official Pro Git book's chapter on rebasing. Read it once you've done a few rebases for real, and it'll click faster.
Recap and what's next
Merge and rebase both combine branches, but they tell different stories. Merge preserves the fork and records the join with a merge commit. Rebase replays your commits onto a new base for a clean linear history, and gives them new hashes in the process, which is exactly why you must never rebase commits you've already shared. Use git rebase main and git rebase -i to polish your local work. Merge when integrating into a branch other people rely on.
You came here from pull requests. Next up, the small file that quietly saves you from committing secrets, build junk, and node_modules: .gitignore and best practices.

Written by
Rhythm Bhiwani
Engineer and relentless builder, happiest reverse-engineering hard problems until they click.
Enjoyed this?
Tap the heart to leave some love.
Be the first to react
Comments
Join the conversation.
Loading comments…


