Toolmingo
Guides7 min read

How to Use Git Rebase (Interactive Rebase, Squash, and More)

A practical guide to git rebase — linear history, interactive rebase to squash/reorder commits, rebase vs merge, conflict resolution, and when not to rebase.

git rebase is one of Git's most powerful — and most misunderstood — tools. It rewrites commit history to produce a clean, linear timeline. This guide covers everything from basic rebasing to interactive rebase, squashing, and conflict resolution.

Quick reference

Command What it does
git rebase main Rebase current branch onto main
git rebase -i HEAD~3 Interactively edit last 3 commits
git rebase --continue Continue after resolving a conflict
git rebase --skip Skip the current conflicting commit
git rebase --abort Cancel the rebase, restore original branch
git rebase -i --root Interactively rebase from the very first commit
git pull --rebase Fetch + rebase instead of fetch + merge
git push --force-with-lease Push rebased branch safely

What rebase actually does

When you rebase branch feature onto main, Git:

  1. Finds the common ancestor of feature and main
  2. Detaches the commits unique to feature
  3. Reapplies them, one by one, on top of main's latest commit
Before rebase:
      A---B---C  feature
     /
D---E---F---G  main

After: git rebase main (from feature branch)
              A'--B'--C'  feature
             /
D---E---F---G  main

The commits A', B', C' have new SHA-1 hashes even if the file changes are identical. That's why rebasing rewrites history.


Basic rebase: update a feature branch

The most common use: bring your feature branch up to date with main without a merge commit.

# Start on your feature branch
git checkout feature/my-work

# Rebase onto main
git rebase main

This is equivalent to "replaying my work on top of the latest main". The result is a linear history — no ugly merge commits.

Compare with merge:

# Merge approach — creates a merge commit
git checkout feature/my-work
git merge main
Approach History shape Extra commits Good for
rebase Linear None Feature branches, cleaner PRs
merge Non-linear One merge commit Shared/public branches
merge --no-ff Non-linear Forced merge commit Preserving branch context

Interactive rebase: rewrite history

git rebase -i (interactive) opens an editor where you choose what to do with each commit.

# Edit the last 3 commits
git rebase -i HEAD~3

The editor shows:

pick a1b2c3d Add login form
pick d4e5f6g Fix typo in form label
pick h7i8j9k Add form validation

# Commands:
# p, pick   = use commit as-is
# r, reword = use commit, but edit the message
# e, edit   = use commit, but stop for amending
# s, squash = meld into previous commit
# f, fixup  = like squash, but discard this commit's message
# d, drop   = remove commit entirely

Squash commits

Combine multiple commits into one before merging a PR:

pick a1b2c3d Add login form
s    d4e5f6g Fix typo in form label
s    h7i8j9k Add form validation

Save and close. Git opens another editor to write the combined commit message.

Fixup (squash silently)

Like squash but discards the later commit messages — useful for "fix typo" commits:

pick a1b2c3d Add login form
f    d4e5f6g Fix typo in form label
pick h7i8j9k Add form validation

Reword a commit message

pick a1b2c3d Add login form
r    d4e5f6g Fix typo in form label   ← will open editor for new message
pick h7i8j9k Add form validation

Drop a commit

pick a1b2c3d Add login form
d    d4e5f6g Fix typo in form label   ← deleted from history
pick h7i8j9k Add form validation

Reorder commits

Simply reorder the lines in the editor. Git replays them in the new order.


Resolving conflicts during rebase

Unlike merge (one conflict resolution), rebase may pause at each conflicting commit and ask you to resolve it.

git rebase main
# CONFLICT (content): Merge conflict in src/auth.ts
# error: could not apply a1b2c3d... Add login form

Resolution workflow:

# 1. Open the conflicting file and fix it
# (look for <<<<, ====, >>>> markers)

# 2. Stage the fixed file
git add src/auth.ts

# 3. Continue the rebase
git rebase --continue
# Git will pause again if the next commit also conflicts

If you want to abandon the entire rebase:

git rebase --abort
# Returns your branch to its exact state before you started

If one commit is impossible to apply cleanly and you want to skip it:

git rebase --skip
# Discards the conflicting commit and continues

git pull --rebase

By default, git pull does a fetch + merge, creating a merge commit even for trivial upstream updates. Use --rebase for a linear history:

git pull --rebase origin main

Set it as the default:

git config --global pull.rebase true

Push after rebasing

Because rebase rewrites history, the remote branch will reject a normal git push:

git push origin feature/my-work
# error: Updates were rejected because the tip of your current branch is behind

You must force-push. Always prefer --force-with-lease over --force:

# Safe: fails if someone else pushed in the meantime
git push --force-with-lease origin feature/my-work

# Unsafe: overwrites without checking
git push --force origin feature/my-work   # avoid unless necessary

Rebase vs merge — when to use which

Situation Use
Update feature branch with latest main rebase
Integrating a feature into main merge (or merge --no-ff)
Cleaning up commits before a PR rebase -i (squash)
Shared/public branch (others have pulled it) merge — never rebase
Long-lived branch with frequent upstream changes rebase + resolve conflicts per commit
Preserving the exact sequence of events merge

The golden rule: never rebase shared history

Never rebase commits that exist on a remote branch other people have pulled.

When you rebase, the old commits still exist on teammates' machines. After you force-push, their history diverges. When they try to push or pull, Git gets confused and they end up with duplicate commits.

Safe to rebase: branches only you have pushed (feature/your-name branches).

Never rebase: main, develop, or any branch others actively use.


Practical patterns

Pattern 1: Clean up a messy feature branch before PR

git checkout feature/auth
git log --oneline
# 3f9a2c1 wip
# 2b8d0e4 fix lint
# 1a7c9f3 more wip
# 0d6b8e2 Add JWT authentication

git rebase -i HEAD~4
# squash first 3 into the bottom one
# write a clean commit message: "Add JWT authentication with refresh tokens"

git push --force-with-lease origin feature/auth

Pattern 2: Sync a long-running branch with main

git checkout feature/big-refactor
git fetch origin
git rebase origin/main
# resolve conflicts commit by commit
git push --force-with-lease origin feature/big-refactor

Pattern 3: Split a commit (using edit)

git rebase -i HEAD~1
# change "pick" to "edit"

# Git pauses at that commit
git reset HEAD~1          # unstage the commit, keep changes in working tree
git add -p                # stage only the first logical change
git commit -m "Add user model"
git add -p                # stage second change
git commit -m "Add user service"

git rebase --continue

Common mistakes

Mistake Why it's a problem Fix
Rebasing main or develop Rewrites shared history, breaks teammates' repos Only rebase private branches
git push --force without --lease Overwrites someone else's push silently Always use --force-with-lease
Forgetting git rebase --continue after resolving Leaves rebase in a stuck state Always git add then --continue
Squashing a commit that shouldn't be squashed Can mix unrelated changes Review the diff before squashing
Rebasing with uncommitted changes Git refuses to start git stash first, then rebase
Using git rebase --skip carelessly Silently loses work Only skip if you're sure the commit is redundant

FAQ

What's the difference between git rebase and git merge?
Both integrate changes from one branch into another. Merge preserves the full branching history with a merge commit. Rebase rewrites history to look as if you branched off the latest tip, producing a linear history.

Does rebase lose my commits?
No — it rewrites their SHA hashes and re-applies the same changes. Your code changes are preserved. The old commits still exist in Git's reflog for ~30 days, so you can recover them with git reflog + git reset.

Why does my rebase have more conflicts than a merge would?
Rebase applies commits one at a time, so each commit can conflict separately. A merge collects everything into one big conflict. More conflicts isn't necessarily worse — each one is smaller and easier to reason about.

Can I rebase onto a different remote branch?
Yes. git rebase origin/staging rebases your current branch onto the remote staging branch (after git fetch).

What is --autosquash?
If you name a commit fixup! <original message> or squash! <original message>, git rebase -i --autosquash automatically places and marks those commits as fixup or squash in the interactive editor.

git commit -m "fixup! Add login form"
git rebase -i --autosquash HEAD~5

Is it safe to rebase a PR branch after the PR is open?
Yes — force-push after rebasing and GitHub/GitLab will update the PR automatically. Just communicate with reviewers so they're not in the middle of leaving comments.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools