Back
GitoryxGitoryx

Interactive Rebase Guide: Clean Up Your Git History

Interactive rebase is the most powerful tool for rewriting your commit history. This guide covers squashing, rewording, dropping, and reordering commits, step by step.

Advanced13 min readUpdated

On this page

What is interactive rebase?

git rebase -i (interactive rebase) opens an editor listing your commits, each prefixed with an action keyword. You change the keywords to rewrite history: squash merges commits, reword edits messages, drop removes commits, edit pauses so you can amend, and reorder lets you rearrange the sequence.

The short version

  1. 1Start: git rebase -i HEAD~N (N = number of commits to edit)
  2. 2In the editor: change pick to squash, fixup, reword, or drop
  3. 3Save and close: Git applies the changes, pausing for conflicts or message edits
  4. 4Resolve any conflicts: git add <file> then git rebase --continue
  5. 5Push the rewritten branch: git push --force-with-lease

Why it matters

You've been working on a feature for two days. Your commit history looks like this: 'WIP', 'fix', 'fix again', 'actually fix', 'typo', 'debug log remove this'. Now you're opening a PR and you don't want your team to see that mess, or worse, have it live in the repo forever.

A clean commit history isn't vanity: it's documentation. When someone runs git bisect to find a regression, or git blame to understand why a line changed, each commit should tell a clear story. Interactive rebase is the tool that lets you rewrite history before it's shared, turning a chaotic work log into a readable narrative.

Where it usually goes wrong

  • Running git rebase -i on a branch that has already been pushed and shared
  • Squashing too aggressively: one giant commit tells no story either
  • Forgetting to force-push after rewriting a branch (git push --force-with-lease)
  • Getting confused by the reversed order in the rebase editor (oldest commit first, newest last)

Interactive rebase, step by step

  1. Step 1: Start an interactive rebase

    Run git rebase -i HEAD~N where N is the number of commits back you want to edit. Git opens your editor with a list of those commits, oldest at the top.

    Terminal
    # Rebase the last 4 commits interactivelygit rebase -i HEAD~4# Rebase all commits since branching from maingit rebase -i main# Rebase from a specific commit (exclusive - that commit is not included)git rebase -i a3b2c1d# The editor opens with something like:# pick f7a1b2c WIP: user auth# pick 3d9e4f5 fix# pick a1c2d3e fix again# pick 8b7e6f4 Add user authentication module

    Tip: The list shows oldest commit at top, newest at bottom. This is the opposite of git log, which shows newest first. The rebase replays commits top to bottom.

  2. Step 2: Learn the rebase action keywords

    Each line in the editor starts with an action. Change the keyword to control what happens to that commit.

    Terminal
    # Available actions (use the full word or just the first letter):# pick   p  - keep the commit as-is# reword r  - keep the commit, but edit its message# edit   e  - pause rebase here so you can amend the commit# squash s  - merge into the previous commit, combining messages# fixup  f  - merge into the previous commit, discard this message# drop   d  - remove this commit entirely# exec   x  - run a shell command after this commit# Example: squash 3 WIP commits into the last one# pick f7a1b2c WIP: user auth# squash 3d9e4f5 fix# squash a1c2d3e fix again# reword 8b7e6f4 Add user authentication module

    Tip: fixup is like squash but silently discards the squashed commit's message: ideal for 'typo', 'fix', 'wip' commits where the message adds no value.

  3. Step 3: Squash commits into one

    The most common use: combine several small commits into a single meaningful one. Mark all commits you want to merge with squash (or s), keeping the top commit as pick. Git prompts you to write a combined message.

    Terminal
    # Before: 4 noisy commits# pick a1b2c3 Add login form HTML# squash d4e5f6 Add form styles# squash 7g8h9i Wire up form submit handler# squash j0k1l2 Add form validation# Git opens another editor to write the combined message:# This is a combination of 4 commits.# Add login form HTML# Add form styles# Wire up form submit handler# Add form validation## Edit to: "Add login form with validation"# Save and close → one clean commit
  4. Step 4: Reword a commit message

    Use reword (or r) to fix a bad commit message. The commit content stays identical, only the message changes. Git pauses and opens your editor for each rewarded commit.

    Terminal
    # Change 'reword' on the commits you want to rename# pick  a1b2c3 fix auth bug# reword d4e5f6 wip remove later# pick  7g8h9i add rate limiting# Git pauses at 'd4e5f6' and opens an editor.# Change the message to something meaningful:# "Sanitize email input before passing to auth provider"# Save → rebase continues
  5. Step 5: Drop unwanted commits

    Change pick to drop (or d) to completely remove a commit from history. Use this to remove debug logs, accidentally committed files, or obsolete experiments.

    Terminal
    # Remove a commit entirely# pick  a1b2c3 Add feature flag for dark mode# drop  d4e5f6 console.log debugging session# pick  7g8h9i Clean up feature flag logic# That commit is gone from history after the rebase.# Warning: if later commits depend on the dropped commit,# you may get conflicts during the rebase.

    Careful: Dropping a commit that later commits depend on will cause conflicts during rebase. If that happens, git rebase --abort to start over and reconsider your approach.

    In Gitoryx: Gitoryx's visual rebase editor shows all commits as cards: drag to reorder, click to squash, drop, or reword.How it works
  6. Step 6: Reorder commits

    Physically cut and paste lines in the editor to reorder commits. Git replays them in the new order. Useful when a logically distinct commit got mixed up with unrelated work.

    Terminal
    # Before reordering:# pick a1b2c3 Add dark mode toggle# pick d4e5f6 Fix typo in README   ← should be first# pick 7g8h9i Refactor theme system# After reordering (move the README fix to top):# pick d4e5f6 Fix typo in README# pick a1b2c3 Add dark mode toggle# pick 7g8h9i Refactor theme system

    Tip: Reordering can cause conflicts if commits touch the same lines. Git will pause and ask you to resolve them, just like a merge conflict.

  7. Step 7: Split a commit into two

    Use edit to pause at a commit. Then use git reset HEAD~1 to unstage it, selectively stage and commit the first part, stage and commit the second part, then git rebase --continue.

    Terminal
    # Mark the commit to split as 'edit'# edit a1b2c3 Add user model and admin panel# Rebase pauses at that commit. Now:# Undo the commit but keep the changesgit reset HEAD~1# Selectively commit the first partgit add src/models/user.tsgit commit -m "Add user model"# Commit the second partgit add src/admin/panel.tsxgit commit -m "Add admin panel scaffold"# Resume the rebasegit rebase --continue
  8. Step 8: Push the rewritten branch

    After interactive rebase, your local branch has a different history than the remote. A normal git push will be rejected. Use --force-with-lease: it's safer than --force because it refuses to push if someone else has pushed to the branch since your last fetch.

    Terminal
    # After rebase, push the rewritten historygit push --force-with-lease origin feature/user-auth# Never use plain --force on shared branches# --force-with-lease refuses if the remote has new commits you haven't seen

    Careful: Never rebase a branch that other developers are working on. Rewriting history changes commit SHAs. Anyone who already pulled will have a diverged branch. Interactive rebase is safe only on branches that are private to you.

Mistakes to avoid with interactive rebase

Rebasing a shared branch
Interactive rebase rewrites every commit SHA from the rebase point onward. If teammates have already pulled those commits, their branches will diverge from yours and they'll need to git reset --hard or re-clone. This is one of the most disruptive things you can do to a shared repo.
Fix: Only rebase branches that haven't been pushed, or branches that are exclusively yours. If you've already pushed, coordinate with your team before force-pushing the rewritten history.
Confusing squash and fixup
Both squash and fixup merge commits upward, but squash opens an editor to combine the messages, while fixup silently discards the squashed commit's message. Choosing the wrong one either loses a meaningful message or adds noise from a 'wip' message.
Fix: Use fixup for commits with meaningless messages ('fix', 'wip', 'typo'). Use squash when the messages contain useful context you want to preserve in the combined message.
Squashing too aggressively
Collapsing 30 commits into one 'Add feature X' makes the history clean but kills granularity. Future git bisect runs or blame archaeology become harder when all changes share one commit.
Fix: Aim for cohesive, logically complete commits, not necessarily one per PR. A PR might legitimately have 3–5 meaningful commits that tell the story of how the feature was built.
Forgetting --force-with-lease after rebase
After rewriting history with interactive rebase, git push will be rejected because the remote and local histories diverge. Newcomers often try git pull first, which creates a mess of merge commits that re-introduces the original noisy history.
Fix: After any interactive rebase on a previously pushed branch, always use git push --force-with-lease. Never git pull after rebasing.

Interactive rebase in Gitoryx

Gitoryx has a built-in interactive rebase editor that lets you drag commits to reorder them, click to squash or drop, and edit messages inline, without touching the terminal or memorizing rebase commands.

  • Gitoryx's visual rebase editor shows all commits as cards: drag to reorder, click to squash, drop, or reword.
  • No need to remember action keywords: pick, squash, fixup, drop are available as buttons on each commit card.
  • Edit commit messages inline in the rebase editor before the rebase runs.
  • Gitoryx highlights which commits are already pushed so you know when force-pushing will be required.
  • Conflict resolution during rebase is handled in Gitoryx's integrated diff view, with no terminal conflict markers.

Free plan · no account required · macOS, Windows and Linux

Interactive rebase: frequently asked questions

What is git rebase -i?
git rebase -i (interactive rebase) lets you rewrite the history of a series of commits before sharing them. You can squash, reorder, drop, reword, or split commits using a text editor. It's the primary tool for cleaning up a messy local commit history.
What is the difference between squash and fixup in interactive rebase?
Both merge a commit into the one above it. squash opens an editor so you can write a combined commit message from both commits. fixup silently discards the lower commit's message and keeps only the upper commit's message. Use fixup for 'wip' and 'fix' commits; use squash when the message contains useful information.
Is it safe to use git rebase -i on a pushed branch?
No, unless the branch is exclusively yours. Interactive rebase rewrites commit SHAs. If other developers have pulled those commits, their branches will diverge after you force-push. Only rebase commits that haven't been shared, or coordinate carefully with your team before rewriting a shared branch.
How do I undo an interactive rebase?
If the rebase is still in progress, run git rebase --abort to cancel and return to the original state. If the rebase completed, use git reflog to find the SHA of your branch before the rebase, then git reset --hard <sha> to restore it.
What does 'edit' do in interactive rebase?
Marking a commit as edit pauses the rebase after applying that commit. You can then amend the commit (git commit --amend), split it into multiple commits, or make other changes. Run git rebase --continue when you're done to resume.
How do I squash all commits on my feature branch into one?
Run git rebase -i main (or whatever your base branch is). In the editor, keep the first commit as pick and change all others to squash or fixup. Save, and Git combines them and prompts you for the final commit message.
Why does git push fail after interactive rebase?
Interactive rebase rewrites commit SHAs, so your local branch and the remote branch have diverged histories. Git rejects a normal push to prevent overwriting. Use git push --force-with-lease to push the rewritten history safely.
Can I rebase in the middle of a rebase?
No, you can't start a new rebase while one is in progress. If you're stuck, either git rebase --continue (after resolving conflicts), git rebase --skip (to skip the current conflicting commit), or git rebase --abort (to abandon the rebase entirely).
All Git tutorials →
Gitoryx

Stop fighting Git. Start shipping.

Download the fast, native Git client that developers actually enjoy using.

v1.1.0 · macOS 12+ (Apple Silicon or Intel) · Windows 10+ · Linux x86_64