Interactive rebase (squash, fixup, reword, drop)

git rebase -i opens an editable to-do list of commits so you can reorder, combine, reword, or delete them before sharing your branch.

Why it matters

Work-in-progress history is messy: wip, fix typo, actually fix it. Interactive rebase lets you curate that into a few logical, reviewable commits — the polish step before opening a PR. It is the everyday workhorse of history rewriting and what GitHub’s “rebase and merge” button does under the hood.

How it works

git rebase -i HEAD~5 lists the last 5 commits oldest-first, each prefixed with an action you edit:

CommandShortEffect
pickpkeep the commit as-is
rewordrkeep changes, edit the message
editepause to amend contents or split
squashsmerge into previous, combine messages
fixupfmerge into previous, discard this message
dropddelete the commit entirely

Reordering lines reorders commits. Save and Git replays them top-to-bottom, minting new SHAs. The companion git commit --fixup=<sha> plus git rebase -i --autosquash auto-arranges fixups against their targets — the idiomatic clean-up loop.

Example

pick   a1b2c3d Add parser
fixup  4d5e6f7 fix typo          # folds silently into a1b2c3d
reword 7a8b9c0 Add validation    # editor reopens for new message
drop   0c1d2e3 debug logging     # removed from history

Five commits become three; the fix typo and debug logging messages vanish from the log entirely.

Pitfalls

  • First squash has nothing above itsquash/fixup fold upward; you can’t squash the top (oldest) line, only into a preceding pick.
  • Deleting a line ≠ drop in old Git — pre-2.x removing a line silently dropped the commit, causing accidental data loss; always use explicit drop.
  • Rewriting shared history — same hazard as any rebase: forces a --force-with-lease push and breaks teammates’ clones.
  • Long replays and conflicts — every commit can re-conflict; git rerere and small batches (HEAD~3, not HEAD~50) keep it sane.

See also