Skip to content

Interactive Rebase — Squash, Edit, Reword & Reorder Commits

DodaTech 5 min read

In this tutorial, you'll learn about Interactive Rebase. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

What You'll Learn

Use git rebase --interactive to squash, reword, reorder, and split commits in Git — clean up your branch history before merging into main.

Why It Matters

A messy commit history with "fix typo" and "wip" commits is hard to review and impossible to revert cleanly. Interactive rebase lets you rewrite history so every commit tells a clear, logical story.

Real-World Use

Before merging a feature branch, you squash 12 incremental commits into 3 meaningful ones, reword two vague messages, and drop a debug commit — making the review take 10 minutes instead of an hour.

What Is Interactive Rebase?

Interactive rebase opens an editor where you choose an action for each commit in a range:

pick a1b2c3 Add login form
pick d4e5f6 fix typo
pick f7a8b9 add validation
pick c0d1e2 WIP
pick f3a4b5 finished validation

# Rebase 5 commits onto main
#
# Commands:
# p, pick = use commit
# r, reword = change message only
# s, squash = combine with previous commit
# d, drop = remove commit
# e, edit = stop to amend

The result after squashing and rewording:

pick a1b2c3 Add login form
squash d4e5f6 fix typo
squash f7a8b9 add validation
squash c0d1e2 WIP
pick f3a4b5 Add form validation

This produces 2 clean commits instead of 5 messy ones.

Basic Interactive Rebase

git checkout feature/login
git log --oneline main..HEAD
# a1b2c3 Add login form
# d4e5f6 fix typo
# f7a8b9 add validation
# c0d1e2 WIP
# f3a4b5 finished validation

# Rebase the last 5 commits
git rebase -i HEAD~5

# Editor opens with:
# pick a1b2c3 Add login form
# pick d4e5f6 fix typo
# pick f7a8b9 add validation
# pick c0d1e2 WIP
# pick f3a4b5 finished validation

Change the actions, save, and exit. Git applies them one-by-one.

Squashing Commits

Combine multiple commits into one:

# Before rebase -i, change to:
pick a1b2c3 Add login form
squash d4e5f6 fix typo
squash f7a8b9 add validation
squash c0d1e2 WIP

# Save and close. Git asks for a new combined message:
# Add login form
# fix typo
# add validation
# WIP

# Write a single clear message:
# Add login form with client-side validation
# Result: one commit with the combined changes
git log --oneline -3
# x7y8z9 Add login form with client-side validation
# f3a4b5 finished validation

Rewording Commits

Change a commit message without changing its content:

# In rebase -i, change to:
reword f3a4b5 finished validation

# Save. Git opens another editor for that commit.
# Change "finished validation" to:
# Add server-side validation checks

# Save again. The message is updated.

Reordering Commits

Move commits in the editor to reorder them:

# Before:
pick a1b2c3 Add login form
pick d4e5f6 Add config file    # belongs first
pick f7a8b9 Add validation

# After (move config up):
pick d4e5f6 Add config file
pick a1b2c3 Add login form
pick f7a8b9 Add validation

Git replays them in the new order. If there are no conflicts, the history is cleanly rewritten.

Dropping Commits

Remove a commit entirely:

# Before:
pick a1b2c3 Add login form
pick d4e5f6 debug output
pick f7a8b9 Add validation

# Change to:
pick a1b2c3 Add login form
drop d4e5f6 debug output
pick f7a8b9 Add validation

# The debug commit is gone. Its changes are not applied.

Editing a Commit

Stop at a commit to make changes:

# In rebase -i:
edit a1b2c3 Add login form

# Git stops after applying this commit.
# Make changes:
echo "new field" >> login.py
git add login.py
git commit --amend  # Update the commit
git rebase --continue

Aborting a Rebase

If something goes wrong:

git rebase --abort
# Returns to the original state before rebase started

Mermaid: Interactive Rebase Flow

graph LR
    A[Start: git rebase -i HEAD~N] --> B[Editor opens with commit list]
    B --> C{Choose action per commit}
    C -->|pick| D[Keep as is]
    C -->|reword| E[Edit message]
    C -->|squash| F[Merge into previous]
    C -->|drop| G[Remove commit]
    C -->|edit| H[Stop to amend]
    D --> I[Continue rebase]
    E --> I
    F --> I
    G --> I
    H --> I
    I --> J{Conflicts?}
    J -->|Yes| K[Resolve & git add / git rebase --continue]
    J -->|No| L[Next commit]
    K --> L
    L --> M{More commits?}
    M -->|Yes| C
    M -->|No| N[Done: history rewritten]

Common Pitfalls

Mistake Solution
Rebasing commits already pushed Never rebase public history — use git revert instead
Forgetting to squash before merge Set up branch protection rules
Conflict during rebase git rebase --abort and retry with smaller range
Losing dropped commits by accident git reflog to recover before rebase expires

Practice Questions

  1. What is the difference between squash and fixup in interactive rebase?
  2. How do you abort an interactive rebase that went wrong?
  3. Why should you never rebase commits that have already been pushed to a shared branch?

FAQs

Can I recover dropped commits after rebase?

Yes — use git reflog to find the commit hash before the rebase, then git cherry-pick or git reset --hard to restore it.

What is the difference between rebase and merge?

Rebase rewrites commit history to create a linear sequence, while merge preserves the branch structure with a merge commit. See the Git Merge vs Rebase guide for a detailed comparison.

How does interactive rebase differ from regular rebase?

Regular rebase applies commits without user interaction. Interactive rebase (-i) opens an editor so you can choose actions per commit — squash, reword, reorder, drop, or edit.

Next Steps

Now that you can clean up branch history with interactive rebase, learn Git Worktrees to work on multiple branches simultaneously, or explore Git Hooks to automate quality checks before every commit.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro