Interactive Rebase

Course 3 · Ch 2
Interactive Rebase
Squashing, reordering, splitting, and rewriting commits safely — cleaning up your own history before anyone else sees it

Course 2's rebase chapter covered moving a whole branch onto a new base. Interactive rebase is a different, more surgical use of the same underlying mechanism — Chapter 1's object model, where rebasing creates new commit objects — applied to editing your own commit history directly: reordering commits, combining several into one, splitting one into several, or rewriting messages, all before anyone else has seen them.

Starting an Interactive Rebase

$ # Interactively edit the last 4 commits
$ git rebase -i HEAD~4

This opens your configured editor with a list of the targeted commits, oldest first, each prefixed with an action word (pick by default) — editing this list and saving it tells git exactly what to do with each commit.

pick a1b2c3d Add login form HTML
pick f9e8d7c fix typo
pick 4f3e2d1 Add validation logic
pick 9c8b7a6 WIP debugging, remove later

# Rebase 5d4c3b2..9c8b7a6 onto 5d4c3b2 (4 commands)
#
# Commands:
# p, pick = use commit
# s, squash = use commit, but meld into previous commit
# r, reword = use commit, but edit the commit message
# d, drop = remove commit
# e, edit = stop for amending

The Actions, One at a Time

pick
Keep this commit exactly as is. The default for every line — change nothing for commits you're happy with.
squash
Combine this commit into the one above it, merging their changes into a single commit. You'll be prompted to write a combined message.
fixup
Same as squash, but silently discards this commit's message entirely — useful for "oops, typo" commits that don't deserve their own line in the combined message.
reword
Keep the commit's changes, but stop and let you edit just its message.
drop
Remove this commit's changes from history entirely — exactly what removing a line (or this explicit action) does for a commit you no longer want at all.
edit
Pause the rebase right after applying this commit, letting you amend it, add more changes, or even split it into multiple commits before continuing.

Example: cleaning up the messy history above

pick a1b2c3d Add login form HTML
fixup f9e8d7c fix typo
pick 4f3e2d1 Add validation logic
drop 9c8b7a6 WIP debugging, remove later

Saving this turns four messy commits into two clean ones: "Add login form HTML" (now silently including the typo fix) and "Add validation logic" — with the leftover debug commit gone entirely. This is exactly the kind of cleanup worth doing before opening a PR (Course 1, Chapter 7), so reviewers see a clear, deliberate history rather than your real-time trial and error.

Splitting a Commit

Sometimes a single commit did too much and should really be two. Mark it edit, and when the rebase pauses there:

$ # Rebase paused after applying the commit you marked "edit"
$ # Undo just this commit, keeping the changes in your working directory
$ git reset HEAD~1
# Now stage and commit the changes as two (or more) separate, focused commits
$ git add login.js
$ git commit -m "Add login form validation"
$ git add styles.css
$ git commit -m "Style the login form"

$ # Continue the rebase with the rest of the original list
$ git rebase --continue

Reordering Commits

Simply reorder the lines in the editor before saving — git replays them in whatever order they appear in the list, top to bottom. Useful when a later fix logically belongs before an earlier feature commit, for a cleaner reading order.

Reordering commits that touch the same lines can cause conflicts
If commit B was written assuming commit A's changes already existed, and you reorder B before A, git may hit a conflict trying to apply B without A's context — resolved the same way as any rebase conflict (Course 2, Chapter 3). Reordering is safe in principle, but not magically immune to logical dependencies between commits.

The Golden Rule Still Applies — Even More So Here

Every single action in this chapter rewrites commit history — new hashes, every time, exactly as Chapter 1's object model and Course 2's rebase chapter explained. Interactive rebase is specifically a tool for cleaning up your own, not-yet-shared commits. Running it on commits others have already pulled creates the exact force-push danger covered in Course 2, Chapter 9 — multiplied, since you're potentially rewriting several commits' worth of history at once rather than just rebasing onto a new base.

A practical habit: clean up right before opening the PR, not throughout
Rather than interactively rebasing constantly while still actively working (where you might still want those messy WIP commits as a personal safety net), many developers do one clean interactive rebase pass immediately before opening a PR — turning a realistic, messy development process into a clean, reviewable set of commits, without losing the messy intermediate states until you're confident you don't need them.

Command Reference

CommandWhat it does
git rebase -i HEAD~NOpens an interactive rebase covering the last N commits
pick / squash / fixup / reword / drop / editPer-commit actions available in the rebase editor
git rebase --continueResumes the rebase after resolving a conflict or finishing an "edit" pause
git rebase --abortCancels the entire interactive rebase, restoring the original history (Course 2, Ch3)

Chapter 2 Quick Reference

  • git rebase -i HEAD~N — opens an editable list of the last N commits
  • squash/fixup — combine a commit into the previous one (fixup discards the message)
  • reword — edit just the message; drop — remove the commit entirely
  • edit — pause to amend, add changes, or split a commit into several
  • Reordering — just rearrange lines before saving; can cause conflicts if commits logically depend on each other
  • Golden rule: only on commits nobody else has pulled — same rewriting danger as Course 2, Chapter 9, multiplied
  • Practical habit: one clean interactive rebase pass right before opening a PR
  • Next chapter: reflog and disaster recovery — undoing even a bad reset or rebase