Skip to content
Rochester, NY design, systems, study tools, and experiments Built in public

Git: rebase vs merge

Merge preserves history exactly as it happened, with a merge commit. Rebase rewrites your branch's commits onto a new base for a linear history. Both achieve the same end state; they differ in what the log looks like and what's safe to do after.

tools git version-control workflow 2026-04-15

git merge and git rebase solve the same problem — combining work from one branch into another — but they leave very different histories behind. Knowing which to reach for is mostly about who else can see your branch.

Merge — preserves history

git checkout feature
git merge main

This creates a new merge commit with two parents (your feature branch tip and main's tip). The graph forks and rejoins; every commit you made is preserved exactly as it happened, in the order it happened.

Pros: - Honest log: shows when branches actually diverged and joined - Non-destructive: existing commits keep their hashes - Always safe on shared branches

Cons: - Lots of merge commits clutter git log on long-running branches - The first-parent line through history is muddier

Rebase — rewrites history

git checkout feature
git rebase main

This takes every commit on your feature branch since it diverged from main, sets your branch base to main's tip, and replays each commit on top as if you had started from there originally. The result is a linear history: main commits, then your commits, no fork.

Each replayed commit gets a new SHA — the old commits still exist in the reflog briefly, but the visible history has been rewritten.

Pros: - Linear, easy-to-read log - Bisect works cleanly - No merge-commit noise on the main line

Cons: - Each replayed commit must be re-resolved if conflicts exist (one round of conflict resolution per commit, not one for the whole branch) - Dangerous on shared branches — anyone else who pulled the old commits now has a divergent local copy

The golden rule

Never rebase a branch that other people have pulled.

If you rewrite history on a shared branch, your collaborators' local copies still reference the old commits. They'll either get confused merges or, worse, push the old commits back, undoing your rebase.

Safe to rebase: your own feature branch before opening a PR, your own local branch that no one has fetched. Not safe to rebase: main, master, develop, any branch with origin/ collaborators.

Practical workflow

  1. Work on a feature branch.
  2. Periodically git fetch origin && git rebase origin/main to keep up to date while the branch is private.
  3. Open a PR.
  4. After approval, either:
  5. Merge commit (default) — preserves the PR as a discrete unit in history
  6. Squash and merge — collapses the whole PR to one commit on main
  7. Rebase and merge — replays each commit individually onto main

The choice is project culture. This repo prefers regular merge commits with descriptive messages.

Recovering from a bad rebase

git reflog shows every position your HEAD has been at, including pre-rebase. Find the SHA from before the rebase and git reset --hard <sha> to restore. The reflog is local-only — it can't recover a botched rebase that someone else has already pulled.