Rebasing
Rewrite commit history for a clean, linear project log — and know when not to
Rebasing is Git's tool for rewriting history to keep it clean and linear. It's powerful and, for many teams, a daily habit — but it comes with one firm rule you must respect. Let's build the intuition first.
Rebase vs Merge
Both combine work from two branches, but they tell different stories.
Merge preserves history exactly as it happened, creating a merge commit where branches meet:
main ─ A ─ B ─────── M
↖ ↗
feature C ── D
Rebase replays your commits on top of the latest target, as if you'd started your branch from there. The result is a straight line:
main ─ A ─ B
feature after rebase: A ─ B ─ C' ─ D'
Notice C and D became C' and D' — new commits with new SHAs. Rebase doesn't move commits; it recreates them. That detail drives the golden rule below.
Rebasing onto an Updated main
The classic use: main moved forward while you worked, and you want your feature branch to sit on top of the latest main with no merge commit.
git switch feature/search
git fetch origin
git rebase origin/main
Git replays each of your commits on top of the new main. If a replayed commit conflicts, Git pauses just like a merge — resolve it, then continue:
# fix the conflicted files, then:
git add <files>
git rebase --continue
# or bail out entirely:
git rebase --abort
A rebased branch produces a clean, linear history with no "Merge branch 'main'" noise. When your PR merges, the project log reads like a tidy sequence of intentional changes rather than a tangle.
Interactive Rebase: Polish Your Commits
git rebase -i lets you rewrite a series of your own commits before sharing them — squash several WIP commits into one, reword messages, reorder, or drop commits entirely.
git rebase -i HEAD~3 # edit the last 3 commits
Git opens an editor listing them with an action per line:
pick a1b2c3d feat: add search input
squash e4f5g6h fix typo
squash i7j8k9l wip
Changing the last two to squash collapses all three into a single, clean commit. Common actions:
pick— keep the commit as-isreword— keep the commit, edit its messagesquash— merge this commit into the previous onedrop— delete the commit entirely
The payoff: your PR shows one coherent commit instead of ten messy "wip" and "fix" steps.
The Golden Rule of Rebasing
Never rebase commits that others have already pulled.
Because rebase creates new commits (C', D'), the originals (C, D) still exist on your teammates' machines. Rebasing shared history forces everyone into a painful divergence. So:
- ✅ Rebase your own local, unpushed branch freely — clean it up before opening a PR.
- ❌ Never rebase
mainor any branch others are building on.
Local & private → rebase away, tidy your history
Shared & pushed → use merge/revert, leave history intact
Merge is always safe; rebase is safe only on private history. When you're unsure whether someone else has your commits, choose merge. You can always rebase local work before it's ever shared.