The earlier Merging lesson covered one way to combine branches. Rebasing achieves a similar goal — bringing a branch up to date with another — through a genuinely different mechanism, with a different result.
Rather than creating a merge commit joining two histories, rebase replays a branch's commits one by one on top of another branch's latest commit — rewriting history as if the branch had been created from that newer point all along.
git switch feature-login
git rebase main
# feature-login's commits are now replayed on top of main's latest commit| git merge | git rebase |
|---|---|
| Preserves exactly what happened, including a merge commit showing where branches joined | Rewrites history into a single clean, linear line — no merge commit |
| Never changes existing commits' hashes | Changes every rebased commit's hash — they become new commits entirely |
| Safe on any branch, shared or not | Only safe on a branch nobody else has already pulled |
Never rebase shared history
Never rebase a commit that's already been pushed and shared with anyone else. Rebase rewrites commit history — a teammate who already pulled the old commits ends up with a repository that looks like it diverged from everyone else's, and untangling it is genuinely painful. Rebase a local, unshared branch freely; never rebase main, or a branch someone else is also working on.
# Squash several small "wip" commits into fewer, meaningful ones,
# before opening a pull request — safe because the branch isn't shared yet
git rebase -i HEAD~5| Situation | Reasonable choice |
|---|---|
| A shared branch, or already-pushed commits | git merge — never rebase these |
| A local, not-yet-pushed feature branch, wanting a clean history | git rebase main is a common, safe choice |