Table of Contents

Introduction

git rebase -i is how you tidy a branch before anyone else sees it: fold the "fix typo" commit into the commit it fixes, reword a message, drop an experiment. It's a plain rebase with one extra step, where Git opens an editor containing a to-do list and does whatever you leave in it.

In this article, we'll:

  1. Look at the to-do list Git generates and the verbs it accepts
  2. Watch a rebase that squashes one commit into the one before it
  3. Cover the same caution that applies to any rebase

What is git rebase -i?

git rebase -i <upstream> finds the commits on your branch since <upstream> and opens an editor with one line per commit, oldest first, each starting with pick. You edit the verbs and the order, save, and Git replays the commits according to the list. Every replayed commit is new, with a new hash, exactly as in a plain rebase.

The to-do list

For our sample repo, git rebase -i main opens:

pick fc19889 Add search box
squash e5869f0 Fix typo in search box
pick 1117a34 Add search tests

We've already changed the second line from pick to squash. The verbs you'll use most (the git rebase documentation lists a few more, such as exec and break):

  • pick keeps the commit as is.
  • reword keeps the change and opens the editor for a new message.
  • edit stops after applying the commit so you can amend it.
  • squash folds the commit into the previous one and lets you edit the combined message.
  • fixup is squash but keeps the previous commit's message and discards this one's.
  • drop (or deleting the line) leaves the commit out.

Reordering lines reorders the commits.

Watch it happen

Our sample repo has feature checked out, with a todo list that squashes the typo fix into the commit before it. Here's the replay git-sim draws for that to-do list:

  1. Before: HEAD is attached to feature at 1117a34, three commits branched off 96c4fc2. main has moved on to 8c02d5b.
  2. "Add search box" is picked, and Git replays it onto main as a new commit.
  3. "Fix typo in search box" is squashed into it. Its changes go into that same new commit, and no separate commit is created.
  4. "Add search tests" is picked and replayed on top.
  5. feature moves to the last new commit, and the three originals are no longer reachable from a branch. The branch now has two commits where it had three.

Is it safe?

Caution git-sim pre-flight

Replays 3 commit(s) from feature onto main — every replayed commit gets a NEW hash.

The way back

  • Original commits stay in the reflog: git reset --hard 1117a34

The originals stay in the reflog, so the rebase itself can be undone. The risk is the same as for plain rebase: if the branch has been pushed and others have it, rewriting it causes trouble for them. Interactive rebase is for branches that are still yours.

My habit while working is to commit small and often, with messages like "wip" and "fix", and then run git rebase -i main before opening a pull request to fold them into a few commits a reviewer can follow. The --autosquash option, paired with git commit --fixup <sha> while working, does most of that list-editing for me now.

How to undo it

git reflog
git reset --hard <sha-before-the-rebase>

or git reset --hard ORIG_HEAD right afterwards. If you're partway through and want out, git rebase --abort returns the branch to where it started.

Try it on your repository

pip install git-sim
git-sim rebase -i main --todo todo.txt

git-sim takes the to-do list as a file and replays it on your own graph, so you can see the resulting history before running the real rebase.

Common questions

What does git rebase -i do?

It lets you edit the list of commits to be replayed: reorder them, squash several into one, reword messages, or drop commits. Then it replays them as new commits.

What is the difference between squash and fixup?

Both fold a commit into the previous one. squash lets you edit the combined message, while fixup discards the folded commit's message and keeps the previous one's.

How do I squash the last three commits?

git rebase -i HEAD~3, then change the second and third lines from pick to squash (or fixup), save, and edit the combined message. Pro Git's Rewriting History chapter walks through the same squash.

How do I abort an interactive rebase?

git rebase --abort while it's in progress. After it finishes, git reset --hard ORIG_HEAD or a reflog entry restores the original branch.

Summary

In this article, we looked at the to-do list git rebase -i generates and the verbs it accepts, watched a replay that squashed two commits into one, and covered how to undo it.

Next steps

git rebase explains the replay itself. git commit --amend is the shortcut when only the last commit needs fixing.