Interactive Rebase in Git: Squash, Reword, Reorder, Edit and Drop Commits

Interactive rebase turns a messy branch into a clean, reviewable story before you open a pull request. In this lesson you will squash, reword, reorder, drop, edit and split commits, and use the fixup and autosquash workflow.

Advertisement

📖 What You’ll Learn: what interactive rebase is, starting it and reading the todo list, squash vs fixup, reword, reorder and drop, editing and splitting older commits, the fixup and autosquash workflow, conflicts, aborting and recovering, and when rewriting is safe.


🧬 What Is Interactive Rebase?

Before you share a branch, its history is often messy: “WIP”, “fix typo”, “really fix test”, commits in the wrong order. Interactive rebase (git rebase -i) lets you edit your own commits before others see them:

  • Squash several small commits into one.
  • Reword commit messages.
  • Reorder, drop or split commits.
  • Edit the content of an older commit.

It is one of the most useful tools for producing clean pull requests. It builds on git rebase.

⚠️ Common mistake: Only rewrite commits that are not yet shared, or that are on your own branch. Rewriting commits on main or other shared branches breaks your teammates’ history.


▶️ Start an Interactive Rebase

git log --oneline -5
# e5f6a7b Fix typo in test name
# d4e5f6a WIP
# c3d4e5f Add checkout tests
# b2c3d4e Add cart tests
# a1b2c3d Add login tests

git rebase -i HEAD~4          # edit the last 4 commits
# or: git rebase -i main      # edit every commit on this branch since it left main

Git opens your editor with a todo list, oldest commit first:

pick b2c3d4e Add cart tests
pick c3d4e5f Add checkout tests
pick d4e5f6a WIP
pick e5f6a7b Fix typo in test name

# Commands:
# p, pick   = use commit
# r, reword = use commit, but edit the commit message
# e, edit   = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup  = like "squash" but keep only the previous commit's message
# d, drop   = remove commit
# x, exec   = run command (the rest of the line) using shell

Change the words at the start of lines, reorder lines if needed, then save and close the editor. Git replays the commits following your instructions.

💡 Tip: The order in the todo list is the reverse of git log: the top line is the oldest commit.


🗜️ Squash and Fixup: Combine Commits

Fold “WIP” and “Fix typo” into “Add checkout tests”:

pick b2c3d4e Add cart tests
pick c3d4e5f Add checkout tests
fixup d4e5f6a WIP
fixup e5f6a7b Fix typo in test name
CommandKeeps the commit’s changesKeeps its message
squash (s)✅ Merged into the previous commit✅ Git asks you to edit the combined message
fixup (f)✅ Merged into the previous commit❌ Discarded silently

Result:

f1a2b3c Add checkout tests
b2c3d4e Add cart tests
a1b2c3d Add login tests

✏️ Reword: Fix Old Commit Messages

reword b2c3d4e Add cart tests
pick   c3d4e5f Add checkout tests

Git stops at that commit and opens the editor for the new message. Great for applying Conventional Commits before opening a PR.


🔀 Reorder and Drop

Move lines up or down to reorder commits, or replace pick with drop (or delete the line) to remove a commit entirely.


🛠️ Edit an Older Commit

edit b2c3d4e Add cart tests
pick c3d4e5f Add checkout tests

Git stops after applying that commit:

# change files, then:
git add tests/cart.spec.ts
git commit --amend --no-edit
git rebase --continue

Split one commit into two

At an edit stop:

git reset HEAD~                       # undo the commit, keep its changes unstaged
git add tests/cart.spec.ts
git commit -m "Add cart tests"
git add src/pages/CartPage.ts
git commit -m "Add CartPage page object"
git rebase --continue

⚡ The Fixup Workflow (Autosquash)

Found a mistake in a commit from earlier on your branch? Create a fixup commit that targets it, then let Git place and squash it automatically:

git commit --fixup c3d4e5f            # creates "fixup! Add checkout tests"
git rebase -i --autosquash main       # the fixup line is already moved and marked

Set git config --global rebase.autoSquash true to make --autosquash the default.


🧯 Conflicts, Aborting and Recovering

  • Conflicts are resolved as usual: fix files, git add, git rebase --continue (merge conflicts).
  • git rebase --abort cancels the whole interactive rebase.
  • Finished but unhappy? Find the old position in git reflog and git reset --hard HEAD@{n}.
  • Already pushed your branch? Update it with git push --force-with-lease (push).

📝 Assignment

  1. On a new branch in git-practice, make five commits including “WIP” and “fix typo”.
  2. Use git rebase -i to fixup the two noisy commits into the right ones.
  3. Reword one message to Conventional Commits style.
  4. Reorder two commits and drop one.
  5. Use edit to split one commit into two.
  6. Create a fixup commit with --fixup and squash it with --autosquash.
  7. Undo the whole exercise with git reflog and git reset --hard.

❓ FAQ

🤔 How do I squash commits in Git?

Run git rebase -i HEAD~N, keep the first commit as pick, change the following ones to squash (or fixup), save and close the editor.

🤔 What is the difference between squash and fixup?

Both merge a commit into the previous one. Squash lets you combine and edit the messages; fixup discards the fixup commit’s message.

🤔 How do I change an old commit message?

git rebase -i HEAD~N, change pick to reword for that commit, save, then enter the new message.

🤔 How do I cancel an interactive rebase?

git rebase --abort while it is in progress, or reset to the previous position from git reflog after it finished.

🤔 Is it safe to rebase -i a pushed branch?

Only if it is your own branch and nobody else builds on it; then push with --force-with-lease. Never rewrite shared branches like main.


🎯 Next Steps

🎬 Learn Git and GitHub step by step: watch the series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

3 thoughts on “Interactive Rebase in Git: Squash, Reword, Reorder, Edit and Drop Commits”

Leave a Comment