Back
GitoryxGitoryx
Advanced13 min read

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.

The Problem

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.

Common mistakes developers make with this:

  • 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)

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.

What is Rebase Guide: Clean Up Your Git History?

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.

Step-by-Step Guide

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.

bash
# Rebase the last 4 commits interactively
git rebase -i HEAD~4

# Rebase all commits since branching from main
git 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

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

Learn the rebase action keywords

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

bash
# 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

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

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.

bash
# 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

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.

bash
# 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

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.

bash
# 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.

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.

See this workflow in Gitoryx. Gitoryx's visual rebase editor shows all commits as cards — drag to reorder, click to squash, drop, or reword.

Free download
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.

bash
# 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

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

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.

bash
# 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 changes
git reset HEAD~1

# Selectively commit the first part
git add src/models/user.ts
git commit -m "Add user model"

# Commit the second part
git add src/admin/panel.tsx
git commit -m "Add admin panel scaffold"

# Resume the rebase
git rebase --continue
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.

bash
# After rebase, push the rewritten history
git 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

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.

Common Mistakes to Avoid

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.

Gitoryx — visual Git client for macOS & Windows
GitoryxGitoryx — macOS & Windows

Interactive Rebase Without the Terminal in Gitoryx

  • 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 — no terminal conflict markers.
Download Gitoryx — FreemacOS · Windows · No subscription

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 — 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).

See it in action with Gitoryx

Everything in this tutorial is faster and clearer with a visual Git client. Gitoryx is free, runs natively on macOS and Windows, and built for developers who want to move fast without breaking things.