Lesson 84 of 12125 min read

Interactive Rebase (git rebase -i): Squash, Reword, Drop, Fixup, and Reorder Commits

Learn how git rebase -i gives fine-grained control over a branch's commit history, letting you squash, reword, drop, fixup, and reorder commits.

Author: CodersNexus

Interactive Rebase (git rebase -i): Squash, Reword, Drop, Fixup, and Reorder Commits

The previous lesson covered rebase replaying commits as-is onto a new base. Interactive rebase takes this same replay mechanism and adds a powerful editing layer on top, letting you squash multiple commits together, reword messages, drop unwanted commits entirely, fold small fixes into earlier commits, and reorder the sequence — turning a messy, exploratory commit history into a clean, presentable one before sharing it.

Learning Objectives

  • Launch an interactive rebase and understand its editable todo list format.
  • Use squash and fixup to combine multiple commits into one.
  • Use reword to change a commit's message without altering its content.
  • Use drop to remove a commit entirely, and reorder commits by rearranging lines.

Key Terms to Know Before Using Interactive Rebase

  • git rebase -i <base>: Launches an interactive rebase, opening an editable list of commits and the action to take for each, rather than simply replaying them unchanged.
  • pick: The default interactive rebase action, keeping a commit exactly as it is.
  • squash: Combines a commit with the one immediately before it, prompting to edit a combined commit message.
  • fixup: Like squash, but discards the commit's own message entirely, silently folding its changes into the previous commit.
  • reword: Keeps a commit's changes but opens an editor to change its message.
  • drop: Removes a commit entirely, discarding its changes from the resulting history.

How Interactive Rebase Actually Works

Running `git rebase -i <base>` (interactive mode, via the `-i` flag) opens a text editor showing a **todo list**: one line per commit being replayed, ordered oldest to newest (note: this is the *opposite* order from `git log`, which shows newest first), each prefixed with an action keyword, defaulting to `pick`:

```
pick a1b2c3d Add initial dark mode toggle
pick 9f8e7d6 fix typo
pick 3c4d5e6 address review feedback: rename function
pick 7g8h9i0 fix css variable name
```

Editing this list before saving and closing the editor is what makes the rebase 'interactive' — Git then carries out whatever actions you specified for each commit, rather than simply replaying them all unchanged.

The most commonly used actions:

- **`pick`** (default): keep this commit exactly as-is.
- **`squash`** (or `s`): combine this commit with the one immediately *before* it in the list, prompting you to write a new, combined commit message for the merged result.
- **`fixup`** (or `f`): like squash, but silently discards this commit's own message entirely, keeping only the previous commit's message — ideal for small correction commits (like `fix typo`) that don't deserve their own explanation in the final history.
- **`reword`** (or `r`): keeps the commit's actual changes unchanged, but opens an editor for just that commit's message, letting you improve wording without touching any code.
- **`drop`** (or `d`): removes the commit entirely, discarding its changes from the resulting history (equivalent to simply deleting its line from the list, or prefixing it with `drop`).

Applying several of these together to the example todo list above — a very common real-world cleanup pattern before opening a pull request:

```
pick a1b2c3d Add initial dark mode toggle
fixup 9f8e7d6 fix typo
reword 3c4d5e6 address review feedback: rename function
pick 7g8h9i0 fix css variable name
```

This keeps the first commit as-is, silently folds the 'fix typo' commit into it (discarding its own message), opens an editor to improve the third commit's message (perhaps to something more descriptive like 'refactor: rename calculateDiscount for clarity'), and leaves the final commit unchanged — resulting in a cleaner, three-commit history instead of the original four, with better messages throughout.

**Reordering** commits is done simply by rearranging the *lines* in the todo list before saving — Git replays them in whatever order you've arranged them, letting you group logically related changes together even if they weren't originally written in that sequence (though reordering commits that depend on each other, where a later commit's changes require an earlier one to already exist, can itself introduce new conflicts during the replay, since the dependency order matters).

This entire editing process happens *before* any actual rebasing takes place — once you save and close the todo list editor, Git executes the plan, potentially pausing for conflicts (exactly as in a normal rebase) or for you to write commit messages (for `squash` and `reword` actions) along the way.

Interactive Rebase Todo List: Visual Walkthrough

Draw a text editor mockup showing the interactive rebase todo list: four lines, each with a dropdown-style action label. Line 1: 'pick a1b2c3d Add initial dark mode toggle'. Line 2: 'fixup 9f8e7d6 fix typo' with an arrow curving up into line 1, captioned 'silently folded into the commit above, message discarded.' Line 3: 'reword 3c4d5e6 address review feedback' with an arrow to a small popup 'Edit message: refactor: rename calculateDiscount for clarity'. Line 4: 'pick 7g8h9i0 fix css variable name' unchanged. Beneath, show the RESULTING history: three clean commits instead of four.

Interactive Rebase Commands: Quick Reference Table

ActionEffect on the CommitTypical Use Case
pickKeep exactly as-isDefault — commits that are already fine
squashCombine with the previous commit, prompts for a new combined messageMerging two meaningfully related commits, keeping context from both
fixupCombine with the previous commit, discards this commit's message entirelySmall correction commits (typos, tweaks) that don't need their own explanation
rewordKeep changes, edit only the messageImproving an unclear or poorly worded commit message
dropRemove the commit and its changes entirelyDiscarding an experimental or unwanted commit

Interactive Rebase: Command Syntax and Examples

# Launch an interactive rebase covering the last 4 commits
git rebase -i HEAD~4

# Editor opens showing (oldest first):
# pick a1b2c3d Add initial dark mode toggle
# pick 9f8e7d6 fix typo
# pick 3c4d5e6 address review feedback: rename function
# pick 7g8h9i0 fix css variable name

# Edit to:
# pick a1b2c3d Add initial dark mode toggle
# fixup 9f8e7d6 fix typo
# reword 3c4d5e6 address review feedback: rename function
# pick 7g8h9i0 fix css variable name

# Save and close -> Git executes the plan:
# - fixup folds 'fix typo' silently into the first commit
# - reword opens an editor for the third commit's message

# Result: git log --oneline now shows 3 clean commits instead of 4

Breaking Down the Interactive Rebase Example

`git rebase -i HEAD~4` targets the last four commits on the current branch for interactive editing (`HEAD~4` as a base reference, from Module 2's relative commit notation). After editing the todo list's action keywords and saving, Git carries out the plan automatically: the `fixup` line silently merges its changes into the preceding commit with no separate message, while `reword` pauses to let you edit just that commit's message. The result, confirmed with a follow-up `git log --oneline`, shows a cleaner three-commit history — exactly the kind of tidying a developer might do to their own local feature branch before opening a pull request, applying Module 5's small-focused-PR philosophy at the level of individual commit quality, not just overall PR scope.

How Interactive Rebase Is Used on Real Engineering Teams

  • Developers commonly use interactive rebase to clean up their own local, not-yet-pushed commit history before opening a pull request, folding away 'wip' and typo-fix commits so the PR's commit history reads clearly for reviewers.
  • Some teams explicitly encourage contributors to interactively rebase and squash minor fixup commits before requesting review, keeping the reviewable history focused on meaningful, well-described changes.
  • The fixup action pairs particularly well with git commit --fixup <hash> (an advanced Git feature that auto-creates a properly labeled fixup commit targeting a specific earlier commit), streamlining this exact cleanup workflow.
  • Reordering commits via interactive rebase is commonly used when a developer realizes, partway through a feature, that grouping related changes together would tell a clearer story than the order they were originally written in.

Interactive Rebase Interview Questions and Answers

Q1. What is the difference between squash and fixup in an interactive rebase?

Both combine a commit with the one immediately before it in the todo list. Squash prompts you to write a new, combined commit message drawing from both commits' original messages. Fixup does the same combination but silently discards the commit's own message entirely, keeping only the previous commit's message — ideal for small correction commits that don't need their own explanation.

Q2. How would you use interactive rebase to remove a commit entirely from a branch's history?

Launch git rebase -i targeting a base that includes the unwanted commit, then either delete that commit's line from the todo list entirely, or change its action keyword to drop, and save. Git will exclude that commit's changes from the resulting history when it replays the remaining commits.

Q3. How does reordering commits work in an interactive rebase, and what risk does it introduce?

Simply rearranging the lines in the todo list before saving changes the order Git replays the commits in. This can introduce new conflicts during the replay if a later commit's changes actually depend on an earlier one that hasn't been replayed yet in the new order, since the dependency between commits matters.

Interactive Rebase Quiz: Test Your Understanding

1. What does the 'fixup' action do during an interactive rebase?

  1. Keeps the commit exactly as-is
  2. Combines the commit with the previous one, discarding this commit's own message entirely
  3. Removes the commit entirely
  4. Opens an editor to change only the commit's message

Answer: B. Combines the commit with the previous one, discarding this commit's own message entirely

Explanation: Fixup merges a commit's changes into the preceding commit, like squash, but silently drops its own message, ideal for small corrections that don't need separate explanation.

2. What is the difference between squash and reword?

  1. They are identical actions
  2. Squash combines two commits together; reword keeps a commit separate but changes only its message
  3. Reword deletes a commit; squash keeps it
  4. Squash only works on the first commit in the list

Answer: B. Squash combines two commits together; reword keeps a commit separate but changes only its message

Explanation: Squash merges the current commit with the one before it. Reword keeps the commit entirely separate and unchanged in content, only opening an editor to revise its message.

3. How do you reorder commits during an interactive rebase?

  1. It's not possible to reorder commits
  2. By rearranging the lines in the interactive rebase todo list before saving
  3. By running a separate git reorder command
  4. Only the first and last commits can be swapped

Answer: B. By rearranging the lines in the interactive rebase todo list before saving

Explanation: The todo list is just editable text — moving lines up or down before saving and closing the editor changes the order Git replays the commits in during the rebase.

Common Interactive Rebase Mistakes Beginners Make

  • Confusing squash and fixup, ending up with an unwanted extra prompt to write a message (squash) when a silent fold (fixup) was actually intended, or vice versa.
  • Forgetting that the interactive rebase todo list is ordered oldest-to-newest, the opposite of git log's newest-first default, and misplacing actions as a result.
  • Reordering commits that have a real dependency on each other without anticipating the new conflicts this can introduce during replay.
  • Running an interactive rebase on commits that have already been pushed and shared, without understanding the consequences (covered in the next lesson's golden rule).

Interactive Rebase: Exam-Ready Quick Notes

  • git rebase -i <base>: opens an editable todo list, oldest commit first (opposite of git log).
  • pick: keep as-is. squash: combine + write new message. fixup: combine + discard message. reword: keep content, edit message. drop: remove entirely.
  • Reordering: rearrange todo list lines before saving; can introduce new conflicts if commits have real dependencies.
  • Common pattern: fixup small correction commits, reword unclear messages, before opening a pull request.

Interactive Rebase: Key Takeaways

  • Interactive rebase gives fine-grained editorial control over a branch's commit history before sharing it.
  • Squash and fixup both combine commits, differing only in whether the folded commit's own message is kept or discarded.
  • Cleaning up local commit history with interactive rebase before opening a pull request directly supports Module 5's emphasis on clear, reviewable history.

Frequently Asked Questions About Interactive Rebase

Q1. What does git rebase -i do differently from a plain git rebase?

A plain rebase simply replays commits unchanged onto a new base. Interactive rebase (-i) opens an editable todo list first, letting you specify an action for each commit — keeping it as-is, combining it with another, rewording its message, or dropping it entirely — before Git carries out the plan.

Q2. What is the difference between squash and fixup?

Both combine a commit with the one before it, but squash prompts you to write a new combined message drawing from both commits, while fixup silently discards the commit's own message, keeping only the previous commit's message unchanged.

Q3. How do I change just a commit's message without touching its content?

Use the reword action in an interactive rebase todo list. It keeps the commit's actual changes exactly as they are, but opens an editor for just that commit's message when the rebase reaches it.

Q4. How do I remove a commit entirely using interactive rebase?

Either delete that commit's line from the interactive rebase todo list, or change its action keyword to drop, then save and close the editor — Git will exclude that commit's changes from the resulting history.

Q5. Can I change the order of my commits with interactive rebase?

Yes, simply rearrange the lines in the todo list before saving. Git will replay the commits in whatever order you've arranged them, though be aware this can introduce new conflicts if a later commit actually depends on changes from an earlier one.

Summary

`git rebase -i <base>` launches an interactive rebase, opening an editable todo list of the commits being replayed (ordered oldest to newest, opposite of `git log`), each with an action keyword defaulting to `pick`. Editing these actions before saving lets you `squash` (combine with the previous commit, writing a new combined message), `fixup` (combine with the previous commit, silently discarding this commit's own message), `reword` (keep the commit's changes but edit its message), or `drop` (remove the commit and its changes entirely) — and simply rearranging the todo list's lines reorders the commits during replay. This gives fine-grained control to clean up a messy, exploratory commit history — folding away typo fixes, improving unclear messages, and removing unwanted experimental commits — before sharing a branch, directly supporting the clear, reviewable pull request history emphasized in Module 5.

Frequently Asked Questions

A plain rebase simply replays commits unchanged onto a new base. Interactive rebase (-i) opens an editable todo list first, letting you specify an action for each commit — keeping it as-is, combining it with another, rewording its message, or dropping it entirely — before Git carries out the plan.

Both combine a commit with the one before it, but squash prompts you to write a new combined message drawing from both commits, while fixup silently discards the commit's own message, keeping only the previous commit's message unchanged.

Use the reword action in an interactive rebase todo list. It keeps the commit's actual changes exactly as they are, but opens an editor for just that commit's message when the rebase reaches it.

Either delete that commit's line from the interactive rebase todo list, or change its action keyword to drop, then save and close the editor — Git will exclude that commit's changes from the resulting history.

Yes, simply rearrange the lines in the todo list before saving. Git will replay the commits in whatever order you've arranged them, though be aware this can introduce new conflicts if a later commit actually depends on changes from an earlier one.