Git
Intermediate 15 min read Git

Rebasing & History Rewriting

Rebase replays commits onto a new base for a linear, readable history. Interactive rebase squashes, rewords, reorders and drops commits; cherry-pick moves individual commits. Rewriting always creates new hashes, so never rewrite shared commits.

rebaseinteractive rebasesquashcherry-pickreflogforce-with-lease
Prerequisites: Branching & Merging
Introduction

What is this?

git rebase takes the commits on your branch and replays them on top of another branch, producing a linear history with new commit hashes. Interactive rebase (-i) lets you squash, reword, reorder, edit or drop commits. git cherry-pick applies a single commit onto your current branch. Rewriting history is safe only for commits you have not shared.

Motivation

Why do you need it?

  • A linear history is easier to read, bisect and review than a web of merge commits.
  • Squashing turns a pile of WIP commits into clean, logical units before a pull request.
  • Rebasing a feature onto main integrates the latest changes without an extra merge commit.
  • Cherry-picking lets you move an urgent hotfix to multiple branches instantly.
Think about it

Mental model

Imagine

Rearranging slides in a presentation deck

Think of

Interactive rebase

Before you present, you reorder, merge and rewrite slides. Interactive rebase does the same to commits before you share them.

Mechanics

How it works

  • git rebase main finds the merge base, then replays your branch commits on top of the latest main tip.
  • Each replayed commit becomes a new commit object with a new parent and therefore a new SHA-1 hash.
  • git rebase -i HEAD~3 opens an editor with a todo list; changing verbs (pick, squash, reword, reorder, drop) changes how commits are replayed.
  • Squashing folds a commit into the one above it; rewording changes the message; dropping removes the commit entirely.
  • If the replayed history was already pushed, you must push --force-with-lease to update the remote.

Rebasing feature onto an updated main.

feature diverges from main
main advances
git rebase main
New hashes
Linear history
Reference

Key commands

git rebase main

Replay your current branch's commits on top of main.

git rebase -i HEAD~3

Interactively edit the last three commits.

git cherry-pick a1b2c3d

Apply a single commit onto the current branch.

git push --force-with-lease origin feature

Safely update a rewritten branch that was previously pushed.

git rebase --continue

Resume a rebase after resolving a conflict.

git rebase --abort

Cancel the rebase and return to the original state.

Hands-on

Examples

Squash WIP commits with an interactive rebase

Squash WIP commits with an interactive rebase
git rebase -i HEAD~3
# The todo list opens in your editor:
# pick a1b2c3d add login page
# pick e4f5g6h wip
# pick i7j8k9l fix typo
#
# Change the middle verbs so only the first stays 'pick':
# pick a1b2c3d add login page
# squash e4f5g6h wip
# squash i7j8k9l fix typo
#
# Save and close; you get a second editor to write the combined message.
git push --force-with-lease origin feature/login

The three commits collapse into one with the first message as the default. Because the hashes changed, the already-pushed branch needs --force-with-lease to update the remote safely.

Real world

In production

  • Squash WIP commits into clean units before opening a pull request.
  • Keep a feature branch up to date with main by rebasing, then pushing with --force-with-lease.
  • Cherry-pick a critical hotfix from main onto a release branch without merging unrelated work.
  • Clean up a messy local commit series so the merged history is bisectable and auditable.
Guidelines

Best practices

  • Follow the golden rule: never rebase commits that others have based work on or that live on a shared branch.
  • Use --force-with-lease, never bare --force, so you cannot clobber someone else's push.
  • Squash to logical units, not one giant commit; preserve meaningful history.
  • Rebase your feature onto main frequently to shrink conflicts and keep integration easy.
  • Check out git reflog before panicking — rebase mistakes are recoverable.
Watch out

Common mistakes

  • Rebasing a public/shared branch, rewriting history other teammates already have.
  • Force pushing without --with-lease and silently overwriting a collaborator's commits.
  • Squashing away attribution, co-authors or important context in commit messages.
  • Using rebase where a merge is expected on shared branches, breaking downstream fast-forward expectations.
Root cause analysis

Common issues

Error
error: could not apply <hash>... (patch does not apply)
Root cause

The replayed commit conflicts with the new base.

Fix

Resolve the conflict, git add the file, then run git rebase --continue; or git rebase --abort to bail.

Error
! [rejected] feature -> feature (non-fast-forward)
Root cause

Local history was rewritten but the remote still has the old commits.

Fix

Since the rewrite is intentional, push with git push --force-with-lease.

Error
fatal: The previous cherry-pick is now empty
Root cause

The commit's changes are already present in the target branch.

Fix

Use git cherry-pick --skip to drop the empty commit, or --abort to stop.

When things break

Debugging tips

  • git status during a rebase shows which step is in progress and the conflicted files.
  • git rebase --abort returns you to the state before the rebase started.
  • git reflog shows every HEAD movement, including the pre-rebase commits, for recovery.
  • git show HEAD~1 after a rebase confirms whether the commit was rebuilt correctly.
Interviews

Interview checkpoint

Practice

Hands-on lab

Squash and Rewrite with Interactive Rebase
25 min · intermediate
In progress
Objectives
  • Create a commit series with messy history
  • Squash commits with interactive rebase
  • Reword a commit message
  • Recover a dropped commit with reflog

Squash and Rewrite with Interactive Rebase

25 min · intermediate

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which command rewrites and reorders recent commits interactively?

2

Rebasing preserves the original commit hashes.

3

What is the safest way to update a pushed branch after a rebase?

Quick reference

Cheat sheet

Rewriting history
git rebase mainReplay branch onto main
git rebase -i HEAD~nInteractive edit of last n commits
squashFold commit into the previous one
rewordChange a commit message
git cherry-pick HASHApply one commit elsewhere
git push --force-with-leaseUpdate rewritten pushed branch
git rebase --abortCancel the rebase
Go deeper

Official documentation