Skip to content

Git Rebasing

5 min readModern Git Workflows · Rebasing

Rebasing takes a series of commits and replays them onto a different base, producing a new series with the same changes and different commit IDs.

That last part is the whole cluster. Rebasing does not move commits; it creates new ones. Everything powerful about it and everything dangerous about it follows from that single fact.

Start with Git Rebase Explained
Before: feature diverged from main

A trunk lane labelled main with commits A, B and C. A branch lane labelled feature leaves main after commit A with commits D and E.

ABCDEmainfeature
After: new commits D-prime and E-prime on top of main

A single lane containing commits A, B, C, then D-prime and E-prime, with the feature label at the end. The primed commits are new objects containing the same changes as D and E but with different parents and therefore different IDs.

ABCD'E'featureD' and E' are new commits. D and E still exist in the object database until garbage collection.

D' contains the same changes as D and the same message and author. It is not D. A commit’s ID is a hash of its content including its parent, so changing the parent necessarily produces a different object.

This is why the cluster keeps returning to one question: has anyone else seen these commits? If not, rebasing is a free and useful tool. If so, replacing them creates work for everyone who has them.

Linear history. git log reads as a sequence rather than a graph. git bisect walks a straight line. No merge commits to filter out.

Clean branches before review. Nobody needs to see “wip”, “fix typo”, “actually fix it”. Interactive rebase lets you present the work as though you had written it correctly the first time — which makes review faster and the history more useful later.

Conflicts resolved once, near the source. Rebasing your branch onto current main surfaces conflicts while you still have the context, rather than at merge time.

Commits that make sense individually. A branch reshaped into “add the interface”, “add the implementation”, “switch the caller”, “delete the old code” is far easier to review than the same work in the order it was actually written.

Rebasing replaces commits. On a branch only you have, that is harmless. On a branch someone else has pulled, it means:

  • Their local branch and yours no longer share history.
  • Their next git pull produces a confusing merge of the old and new versions.
  • Any work they based on your commits is now attached to commits that are not on your branch.
  • Review comments anchored to specific commits lose their anchors.

None of this destroys data — the original commits survive in the reflog and object database — but recovering is manual and annoying, and it is entirely avoidable.

  1. Lesson 1: 01. Git Rebase ExplainedRebase replays your commits onto a new base, creating new commits with new IDs. Learn the mechanism, the conflict loop and the safety rules.Intermediate12 min read
  2. Lesson 2: 02. Interactive RebaseInteractive rebase lets you reword, reorder, squash, split and drop commits before review. A hands-on guide to the todo list and its commands.Intermediate → Advanced12 min read
  3. Lesson 3: 03. Reordering CommitsReordering commits means rewriting them. Learn how to reorder safely with interactive rebase, handle dependencies, and recover if it goes wrong.Intermediate7 min read
  4. Lesson 4: 04. Squashing CommitsCombine several commits into one with interactive rebase. Learn squash versus fixup, autosquash, and when granular commits are worth keeping.Intermediate9 min read
  5. Lesson 5: 05. Editing Commit HistoryAmend, rebase, revert and reset do different things. A decision framework for changing history, plus recovery when an edit goes wrong.Intermediate → Advanced12 min read
  6. Lesson 6: 06. Rebase vs MergeRebase and merge produce different histories with different trade-offs for auditing, debugging and collaboration. A decision guide, not a verdict.Intermediate11 min read
  7. Lesson 7: 07. When Not to RebaseRebasing shared history creates work for everyone else. Learn the situations where rebasing is the wrong tool, and the nuanced exceptions.Intermediate9 min read

Lesson 1 covers the mechanism: how replay works, the conflict loop, and what --continue, --skip and --abort do.

Lesson 2 covers interactive rebase — the todo list, and the commands that let you reword, reorder, squash, split and drop commits.

Lessons 3 and 4 narrow to two specific operations people search for directly: reordering commits and squashing them.

Lesson 5 is the decision framework for changing history at all: when to amend, when to rebase, when to revert, when to reset, and how to recover from each.

Lesson 6 compares rebasing with merging as integration strategies, without picking a winner.

Lesson 7 covers the situations where rebasing is the wrong tool.

“Rebase” covers several distinct jobs that share a mechanism. Knowing which one you want makes the commands much less confusing.

JobCommandPurpose
Move a branch onto a newer basegit rebase mainBring your branch up to date without a merge commit
Reshape your own commitsgit rebase -i HEAD~5Squash, reword, reorder, split, drop
Move a branch off its parentgit rebase --onto main old-base featureRe-parent a stacked branch
Replay a single commit elsewheregit cherry-pickNot a rebase, but the same replay machinery
Fix the most recent commit onlygit commit --amendThe smallest possible rewrite

The first two account for almost all real use. The third solves the specific problem of a branch built on another branch that has since been squashed or rebased.

Before rewriting anything, four questions:

  1. Has this been pushed? If not, rebase freely.
  2. If pushed, has anyone pulled it? A branch pushed only as a backup is still safe.
  3. Is anyone’s work based on these commits? Stacked branches break; check before rewriting the parent.
  4. Is review in progress? Rewriting invalidates reviewers’ comment anchors. Add commits during review; reshape before or after.

If all four are clear, rebase. If any is uncertain, ask — or merge instead, which never rewrites anything.

From Pillar 1:

  • Git Objects Explained — commits are immutable and identified by content hash. This is why rebasing creates new commits rather than editing existing ones.
  • Understanding HEAD — particularly the reflog, which is the safety net for every operation in this cluster.
  • Understanding the Git Index — rebase conflicts use the same index stages as merge conflicts.

From this pillar:

Every operation in this cluster is recoverable, because Git records where your branch pointed before each step:

Terminal window
git reflog
eee8f01 HEAD@{0}: rebase (finish): returning to refs/heads/feature
84b5d12 HEAD@{1}: rebase (pick): D: first feature commit
68cbf80 HEAD@{2}: rebase (start): checkout main
a1d07c2 HEAD@{3}: commit: E: second feature commit

HEAD@{3} is the branch as it was before the rebase started. Restoring it is one command:

Terminal window
git reset --hard HEAD@{3}

The reflog is local, is never pushed, and expires — 90 days by default for reachable commits, 30 for unreachable ones. That is ample for real recovery, but it means recovery has to happen in the repository where the rewrite occurred.

Start with the mechanism. Interactive rebase and everything after it are variations on the same replay loop.