Rebasing vs. merging — two ways to combine the same work

Merge and rebase solve the exact same problem — getting one branch's commits onto another — but they produce genuinely different-looking history, and picking between them is a real, ongoing team decision, not a matter of one being objectively correct.

Intermediate

3 min read

The same starting point, two different outcomes

Before:

Both merge and rebase start from this same situation: feature branched off main at B, and both branches have since gained independent commits. The branching lesson already covered git merge; this lesson is about the alternative, and the real trade-off between them.

Merge: preserves exactly what happened, including the two-parent commit

After git merge feature (from main):

git merge feature (run from main) creates a merge commit M with two parents, combining both histories exactly as they happened — feature's commits (D, E) stay exactly as they were, unchanged, and the merge commit records the fact that these two lines of work came together at this point. The history is a completely honest record of what actually happened, including every branch and merge point — genuinely useful when how work diverged and reconverged is itself meaningful information.

Rebase: rewrites history to look like it happened in a straight line

After git rebase main (from feature):

After merging feature into main (fast-forward, no merge commit):

git rebase main (run from feature) takes feature's commits and replays them one by one on top of main's current tip — the content of each commit is preserved, but they become entirely new commits (D', E', with different hashes) as if feature had been created from C, not B, from the start. Merging this rebased feature into main afterward is then a clean fast-forward (from the branching lesson) — no merge commit, no two parents, just one clean, linear line of commits, as if the work had happened in that exact order the whole time.

The actual trade-off: honest history vs. clean history

Merge:  history shows exactly what happened, including every branch/merge point
        -> more accurate, but can get visually noisy with many small merges

Rebase: history looks like one clean, linear sequence of commits
        -> easier to read later, but the commit hashes and exact
           timing are no longer what actually happened

Neither is objectively better — this is a genuine, ongoing choice teams make deliberately, usually as a team-wide convention rather than something decided commit by commit. Merge's honesty matters when the branching structure itself carries information worth keeping; rebase's linearity matters when a clean, easy-to-follow git log is worth more than an exact record of how the work actually diverged and came back together.

The one hard rule: never rebase commits that have already been pushed and shared

You:      pushed feature: D -- E
Teammate: already pulled D -- E, and built F on top of E

You then rebase feature: D' -- E'  (different hashes from D and E)
You force-push: your teammate's F is now built on commits that no longer exist upstream

This is exactly the danger the undoing-changes lesson described for reset on shared history, and rebase has the identical risk for the identical reason: rebasing replaces commits with new ones that have different hashes, so if anyone else has already built on the originals, rewriting and force-pushing orphans their work. The rule that follows directly from this: rebase freely on commits that are still entirely local and unshared; once something's pushed and others might depend on it, merge (or a fresh commit) is the safe option instead.

Further reading

Check your understanding

A quick comprehension check — not tracked, not graded, just for you.

1. What's the fundamental output difference between git merge and git rebase for combining the same two branches?

2. Why do a feature branch's commits get entirely new hashes after being rebased, even though the actual code changes are unchanged?

3. Is merge or rebase objectively the correct choice for combining branches?

4. Why is rebasing commits that have already been pushed and pulled by a teammate genuinely dangerous?