Interactive rebase

Git · Advanced · 15 min

Turning a messy series of WIP commits into a clean, reviewable story is what interactive rebase is for.

git rebase -i <base> opens your editor with a todo list of every commit after <base>, oldest first. Each line starts with a command; you edit the list, save, and Git replays the commits accordingly:

  • pick: keep the commit as is.
  • reword: keep it but edit the message.
  • edit: stop after applying it so you can amend it or split it into several commits.
  • squash: meld into the previous commit and combine the messages.
  • fixup: meld into the previous commit and discard this message (fixup -C keeps this one's message instead).
  • drop (or delete the line): remove the commit.
  • exec <cmd>: run a shell command, such as the tests, at that point; the rebase stops if it fails.

Reordering lines reorders commits. Typical use: git rebase -i origin/main to tidy everything your branch adds before opening a PR.

Autosquash saves editing by hand. When you notice a mistake in an earlier commit, fix it and run git commit --fixup=<that-commit>. Later, git rebase -i --autosquash origin/main (or rebase.autoSquash true) moves each fixup under its target, already marked.

To split a commit: mark it edit; when Git stops, run git reset HEAD~, then stage and commit pieces separately, then git rebase --continue.

If you stack branches (part1 on which part2 is built), --update-refs moves those intermediate branch pointers along too.

All the usual rebase rules apply: new commit IDs, so only rewrite commits not yet shared, and git rebase --abort gets you out at any point.

Example

git commit --fixup=3f9a2c1          # "fixup! Add search index"
git rebase -i --autosquash origin/main
# Editor shows (oldest first):
#   pick   3f9a2c1 Add search index
#   fixup  a77b1e0 fixup! Add search index
#   pick   5d2e9f1 WIP
#   pick   8c4b0aa Add search UI
# Change to:
#   pick   3f9a2c1 Add search index
#   fixup  a77b1e0 fixup! Add search index
#   squash 5d2e9f1 WIP
#   reword 8c4b0aa Add search UI
#   exec   make test
git push --force-with-lease

Remember

  • The todo list is oldest-first; reorder lines to reorder commits
  • squash merges messages; fixup discards the fixup's message
  • commit --fixup + rebase --autosquash automates cleanup
  • exec runs tests at any point in the replay

Watch out for

  • Interactive-rebasing commits already merged into a shared branch, creating duplicate commits for everyone.

Check yourself

  1. What is the difference between squash and fixup in the todo list?
  2. In which order does git rebase -i list commits?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: git-scm.com/book/en/v2/Git-Tools-Rewriting-History