Git merge vs rebase.
Stitching two histories together with a join, versus replaying your changes on top to make one tidy line.
When your branch and the main branch have both moved on, you need to combine them. Git offers two ways. A merge ties the two histories together with a single new "merge commit", preserving exactly what happened, branches and all — like joining two roads with a junction.
A rebase instead lifts your commits off your branch and replays them, one by one, on top of the latest main, as if you had started your work from there all along. The result is one clean, straight line of history — like re-laying your road so it continues smoothly from the new starting point.
- Both roads have grown.1
Your branch and main have both moved on. Now you need to combine them.
- Junction added. History honest.2
A merge ties them with one new junction commit — the true forks and joins kept intact.
- 3
Nothing is rewritten, but on a busy project the map turns into crisscrossing lines.
- Pick them up, lay them down again.4
A rebase lifts your commits off and replays them on top of the latest main, one by one.
- 5
The result is one clean, straight line — easy to read and to bisect for a bug.
- Rebase yours, not the shared ones.6
But replay makes new commits. Never rebase ones you’ve already shared — the team still holds the originals.
History honest vs history tidy
Merge keeps an honest record: the merge commit and the branch structure show exactly when work diverged and came back together. That is great for auditability but can make a busy project's history a tangle of crisscrossing lines. Rebase trades that for a clean, linear story that reads like a single sequence of changes, which is much easier to follow and to bisect when hunting a bug — at the cost of no longer reflecting the literal order things happened.
The golden rule of rebasing
Rebase does not move commits, it makes new ones with new identities and discards the originals. That is fine for commits only you have. But never rebase commits you have already shared, because everyone else still has the originals; rewriting them forces a confusing, error-prone reconciliation for the whole team. The common practice is to rebase your own local feature branch to tidy it before sharing, and to merge when integrating shared branches.