Topic 2.4
Interactive Rebase: Squash, Reorder, and Edit History
In one line
git rebase -i opens an editable list of your recent commits, letting you squash messy ones together, reorder them, reword messages, or drop them entirely — the tool for turning a messy work-in-progress history into a clean, reviewable one.
Think of it like this
Editing a rough draft into a final version before anyone else reads it — combining two paragraphs that say the same thing, fixing a typo in an earlier section, deleting a paragraph you decided didn't belong. Interactive rebase does exactly this to your commit history, before you share it.
Key ideas
- 01
git rebase -i <base>(interactive rebase) opens your default editor with a list of every commit between<base>and your current position, each prefixed with the wordpick— this list is itself an editable SCRIPT: reordering the lines reorders the commits, and changing a commit's leading word changes what happens to it. - 02
The key commands available in that list:
pick(keep the commit as-is),reword(keep the change, but let you edit the commit message),squash(combine this commit INTO the one above it, merging their changes and letting you write a new combined message),fixup(like squash, but silently discards this commit's message entirely), anddrop(remove the commit entirely, discarding its changes). - 03
The single most common real use: turning five or six small 'wip', 'fix typo', 'actually fix it this time' commits into ONE clean, well-described commit before opening a pull request — mark the first commit
pickand every commit after itsquash(orfixupif their messages aren't worth keeping), producing one meaningful commit from what was a messy work-in-progress sequence. - 04
Interactive rebase is still fundamentally a REBASE — every commit involved gets a new SHA, and the golden rule from Topic 2.3 applies with full force: only interactively rebase commits that are still entirely local and unshared. Interactively rebasing commits others have already pulled causes exactly the same painful divergence as a regular rebase.
- 05
If an interactive rebase goes wrong mid-way (a conflict you can't resolve, or you realize you made a mistake in the plan),
git rebase --abortcleanly cancels the whole operation and returns you to exactly where you started — genuinely useful to know exists before attempting your first real interactive rebase.
Code & diagrams
Four messy, real commits become one clean, reviewable one.
Turn four messy commits into one clean one.
cd ~/scratch/my-first-repo
git switch -c feature/messy-history main
# Simulate a realistic, messy sequence of small commits
echo "step 1" >> feature.txt && git add feature.txt && git commit -m "wip"
echo "step 2" >> feature.txt && git add feature.txt && git commit -m "wip more"
echo "step 3" >> feature.txt && git add feature.txt && git commit -m "fix typo"
echo "step 4" >> feature.txt && git add feature.txt && git commit -m "actually finish it"
# Clean up the last 4 commits before anyone else sees them
git rebase -i HEAD~4
# Your editor opens something like:
# pick a1b2c3d wip
# pick e4f5g6h wip more
# pick i7j8k9l fix typo
# pick m0n1o2p actually finish it
#
# Change it to:
# pick a1b2c3d wip
# squash e4f5g6h wip more
# squash i7j8k9l fix typo
# squash m0n1o2p actually finish it
#
# Save and close — a second editor screen opens to write the
# combined commit's final message, e.g. "Add the complete feature"
git log --oneline
# now shows ONE clean commit instead of four messy onesExplain it without notes
What's the practical difference between squash and fixup when combining commits in an interactive rebase?
Why is it safe to interactively rebase a feature branch you've been working on alone, but not safe to do the same on main after pushing?
Practice
Create four small, deliberately messy commits on a test branch, then use git rebase -i to squash them into one clean commit with a proper message.
During a practice interactive rebase, deliberately abort it partway through with git rebase --abort and confirm your branch returns to its original, unrewritten state.
Trade-offs
- ↔
Interactive rebase produces a genuinely more readable, professional-looking history, but it takes real practice to get comfortable with (the pick/squash/fixup/drop vocabulary, resolving conflicts mid-rebase if they arise) — many teams solve this more simply by using a hosting platform's 'squash and merge' button on pull requests instead, which achieves a similar clean-single-commit result automatically at merge time without requiring every contributor to learn interactive rebase directly.
Done when you can
I can use git rebase -i to squash several messy commits into one clean commit.
I know the difference between squash (keeps message, editable) and fixup (discards message).
I know git rebase --abort exists and returns me cleanly to my pre-rebase state.