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.
📖 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
| Command | Keeps the commit’s changes | Keeps 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 --abortcancels 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
- On a new branch in
git-practice, make five commits including “WIP” and “fix typo”. - Use
git rebase -ito fixup the two noisy commits into the right ones. - Reword one message to Conventional Commits style.
- Reorder two commits and drop one.
- Use
editto split one commit into two. - Create a fixup commit with
--fixupand squash it with--autosquash. - Undo the whole exercise with
git reflogandgit 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
- 🛟 git reflog: Recover Lost Commits and Branches
- 🔍 git bisect: Find the Commit That Broke Your Code
- 📘 Git and GitHub Tutorial: full course
🎬 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”