Course outline · 0% complete

0/28 lessons0%

Course overview →

Rebase vs merge

lesson 9-1 · ~10 min · 24/28

Recall from lesson 5-3 what happens when both branches have gained commits and you run git merge feature from main: you get the two lines of work joined by a merge commit with two parents.

Diverged branches cannot fast-forward, so Git combines the changes and records the join as a commit that points back into both histories.

This lesson introduces the other way to combine diverged work, one that produces a straight line instead of a join.

Rebase: replay instead of join

While you built your feature branch, main moved ahead. Merge is one answer, but on a busy team main moves daily, and merging it into your branch over and over fills the history with merge commits until the graph reads like tangled wiring. That is harder for humans to follow and slower for tools like git bisect, coming in unit 10, to walk.

Rebase was invented to take main's updates while keeping history a straight line.

$ git switch add-search
$ git rebase main
Successfully rebased and updated refs/heads/add-search.

Rebase lifts your branch's commits off their old starting point and replays them, one at a time, on top of main's newest commit. The result reads as though you had started the work this morning from the latest main, with no merge commit anywhere.

Now the crucial fine print. Replayed commits are new copies with new hashes. The old commits are not moved, because a commit's hash comes from its contents including its parent, so a commit with a different parent is necessarily a different commit. Rebase creates the copies and quietly abandons the originals.

Same changes, same messages, different identities. Hold onto that fact, because it is the thing that decides when rebase is safe.

before: divergedmainadd-searchafter git rebase main: replayed copies, straight linemainnew copies, new hashesadd-search
Rebase re-creates your branch's commits (gold) on top of main's tip. History becomes a straight line, but the replayed commits are new objects with new hashes.

Choosing, and the golden rule

mergerebase
History shapetrue to what happened, with merge commitsstraight line, easy to read
Existing commitsuntouchedreplaced by copies with new hashes
Safe on shared commitsyesno

The golden rule of rebase follows directly from that middle row: never rebase commits you have already pushed to a shared branch.

Teammates hold the original commits. Rebase gives you renamed copies of the same work, so the next push or pull becomes a collision between two versions of the same history, which is genuinely miserable to untangle and usually ends with someone re-cloning.

The safe everyday pattern is simple to state. Rebase your own local, unpushed branch onto fresh main as often as you like, then merge it or open the pull request from lesson 8-1. Local rebase, shared merge.

Beyond that rule, teams differ in taste. Some require a linear history and rebase everything before merging, others prefer merge commits as an honest record. Follow the convention of the team you are on, since both work as long as the golden rule holds.

After a successful git rebase main, the branch's original commits were replaced by new copies with new hashes, replayed on top of main.

Rebase re-creates each commit on the new base. The diffs and the messages carry over unchanged, but the identities are brand new, because each commit now has a different parent and the hash depends on that.

This is precisely why rebasing already-shared commits causes chaos. Other people still hold the originals, so after your rebase there are two sets of commits containing the same work, and Git has no way to know they are meant to be the same thing.

The originals do not vanish immediately, incidentally. They stay in the reflog from lesson 4-3 for a while, which is the escape route if a rebase turns out badly.

The golden rule completes as: never rebase commits you have already pushed, meaning shared with anyone else.

Once others may hold the originals, replacing them with renamed copies splits the team's history into two versions of the same work. Every subsequent pull and push has to reconcile them, and Git cannot do that for you because it has no way to recognize the copies as equivalents.

The division of labor that follows is worth memorizing. Rebase freely on local-only work, where nobody else has the commits, and reach for merge or revert on anything already shared.