Git interactive rebase lets you rewrite a sequence of commits before you share or merge them. You can improve commit messages, combine small corrections, reorder work, split a large commit, or remove an unwanted commit.
Rebasing recreates the affected commits, so their commit IDs change. Use interactive rebase freely on private local work. If the commits are already shared, coordinate with the team before rewriting them.
Create a temporary backup branch before a complex rewrite. It gives you a simple reference even though Git also records earlier branch positions in the reflog.
Start an Interactive Rebase
Run git rebase with -i and identify the commit immediately before the range you want to edit.
Example:
# Rewrite the latest three commits
git branch backup/profile-history
git rebase -i HEAD~3
You can also provide an upstream branch. Git then lists commits that belong to your current branch but are not reachable from that upstream.
# Rewrite local feature commits created after branching from main
git rebase -i main
The editor shows commits from oldest to newest because Git replays the todo list from top to bottom. The upstream commit itself is not included.
Interactive Rebase Commands
| Command | Purpose |
|---|---|
| pick | Keep the commit |
| reword | Keep changes and edit the message |
| edit | Pause to amend or split the commit |
| squash | Combine with the previous commit and edit messages |
| fixup | Combine with the previous commit and discard this message |
| drop | Remove the commit |
| exec | Run a shell command |
| break | Pause at this position |
Reorder, Reword, or Remove Commits
Move a line to reorder a commit. Replace pick with reword to edit only its message, or with drop to remove it. Reordering can cause conflicts when one commit depends on another.
Example todo list:
# Keep the feature, rename the test commit, and remove debugging
pick 91ac341 Add user profile
reword c96a281 Add profile tests
drop 518d732 Add temporary debugging
Squash Related Commits
Place a correction directly below its target and change its action to squash or fixup. Squash opens the combined message for editing; fixup discards the correction's message.
# Produce one focused feature commit
pick 91ac341 Add user profile
fixup 518d732 Fix profile heading
squash c96a281 Add missing profile validation
Use Autosquash
Create a targeted fixup commit, then let --autosquash move it beside the correct commit and mark it as fixup.
# Stage the correction and link it to an earlier commit
git add src/profile.php
git commit --fixup 91ac341
git rebase -i --autosquash main
Edit or Split a Commit
Change pick to edit. When Git pauses, modify files and amend the commit. To split it, reset the paused commit while keeping its changes, then create several smaller commits.
# Split the paused commit while keeping its changes in the working tree
git reset HEAD^
# Create the first focused commit
git add src/profile.php
git commit -m "Add profile model"
# Create the second focused commit
git add tests/profile_test.php
git commit -m "Test profile model"
# Continue replaying the remaining commits
git rebase --continue
Handle Rebase Conflicts
Git stops when it cannot apply a commit cleanly. Open the conflicted files, remove conflict markers, keep the correct content, stage the resolved files, and continue.
# See conflicted paths
git status
# Stage each resolved file and continue
git add src/profile.php
git rebase --continue
Use git rebase --skip only when the current commit is no longer required. Use git rebase --abort to restore the branch to its pre-rebase state.
Run Tests During the Rebase
The exec action or --exec option runs a command after selected commits. Git pauses when the command fails, allowing you to fix the problem before continuing.
# Verify every rewritten commit
git rebase -i --exec "npm test" main
Recover from an Incorrect Rebase
If a completed rebase produced the wrong history, inspect git reflog. Find the branch position recorded before the rebase and create a recovery branch from it.
# Locate the earlier branch tip
git reflog
# Preserve the chosen earlier position
git branch recover-profile HEAD@{5}
Push Rewritten History Safely
A normal push is rejected when the remote branch contains the old history. If the team approves the rewrite, use --force-with-lease. It refuses to overwrite remote work that you have not fetched, making it safer than --force.
# Update a shared branch only after coordination
git push --force-with-lease origin feature/profile
Best Practices
- Rebase a clean working tree and inspect the selected range first.
- Keep a backup branch for complex history edits.
- Write focused commits before using rebase as cleanup.
- Run tests after rewriting and before pushing.
- Avoid rewriting public commits unless collaborators agree.
Conclusion
Git interactive rebase gives you precise control over local commit history. Select the correct range, use the todo commands deliberately, resolve conflicts one commit at a time, and recover through the reflog when necessary. Careful use produces a clearer history without losing the work behind it.