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 demo

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 & Linux
GitoryxGitoryx — macOS, Windows & Linux

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 · Linux · 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, Windows, and Linux, and built for developers who want to move fast without breaking things.