Rebasing
Intuition
Section titled “Intuition”Rewriting history to keep it clean: Rebasing is like rewriting a history book to remove digressions — instead of a messy merge commit that says “combined two timelines,” you get a clean linear narrative. The end result is the same, but the history is easier to follow.
Why it matters: Clean history makes debugging easier (you can git bisect effectively), code review simpler (changes are in logical order), and onboarding faster (new team members can follow the story).
The key insight: Never rebase commits that have been pushed to a shared repository — rewriting published history forces everyone else to reconcile conflicting versions. Rebase only your local, unpushed commits.
What is Rebasing
Section titled “What is Rebasing”Rebasing is the process of replaying a series of commits onto a new base commit. Unlike merging, which creates a new commit with two parents, rebasing rewrites history by creating new commit objects with the same changes but different parent pointers (and therefore different SHA-1 hashes).
Merge vs Rebase: Visual Comparison
Section titled “Merge vs Rebase: Visual Comparison”Before (both branches diverge from commit B):
gitGraph
commit id: "B (base)"
checkout main
commit id: "D (main)"
checkout feature
commit id: "C"
commit id: "E"After git merge feature (non-linear history):
gitGraph
commit id: "B (base)"
checkout main
commit id: "D (main)"
checkout feature
commit id: "C"
commit id: "E"
checkout main
merge feature id: "F (merge)"After git rebase main (linear history):
gitGraph
commit id: "B (base)"
commit id: "D (main)"
commit id: "C" (rebased)"
commit id: "E' (rebased)"Note that C' and E' are new commits with different hashes than C and E. The original commits still exist in the object store (reachable via the reflog) but are no longer on any branch.
How Rebase Works Internally
Section titled “How Rebase Works Internally”The git rebase operation performs the following steps:
- Find the merge base: Identify the common ancestor between the current branch and the target branch.
- Save the current state: Record the current HEAD and branch reference.
- Move HEAD to the target branch (e.g.,
main). - Replay each commit: For each commit in the original branch (from oldest to newest), apply its diff onto the new base, creating a new commit object.
- Move the branch pointer to the tip of the new commit chain.
flowchart TD
A["Find merge base (commit B)"] --> B["Move HEAD to main (commit D)"]
B --> C["Cherry-pick commit C onto D → create C'"]
C --> D["Cherry-pick commit E onto C' → create E'"]
D --> E["Move feature branch to E'"]
style A fill:#fff3e0
style E fill:#e8f5e9Each “replayed” commit is effectively a cherry-pick: Git computes the diff introduced by the original commit and applies it to the new base. This means:
- If a commit’s changes cleanly apply to the new base, the rebase succeeds.
- If there are conflicts, Git pauses and asks you to resolve them before continuing.
Basic Rebase
Section titled “Basic Rebase”## Rebase the current branch onto main$ git switch feature-auth$ git rebase main
## Rebase a specific branch onto main (without switching)$ git rebase main feature-authAbort a Rebase
Section titled “Abort a Rebase”If conflicts become unresolvable:
$ git rebase --abort# Restores the branch to its original state before the rebaseContinue a Rebase
Section titled “Continue a Rebase”After resolving a conflict:
$ git add <resolved-file>$ git rebase --continueSkip a Commit
Section titled “Skip a Commit”If a commit’s changes are no longer relevant (e.g., a fix that was already applied upstream):
$ git rebase --skipInteractive Rebase
Section titled “Interactive Rebase”Interactive rebase (git rebase -i) is one of Git’s most powerful features. It allows you to rewrite the commits on your branch: reorder, edit, squash, split, or drop commits.
# Rebase the last 5 commits interactively$ git rebase -i HEAD~5
# Rebase all commits since diverging from main$ git rebase -i mainThe Todo List
Section titled “The Todo List”Interactive rebase opens an editor with a todo list:
pick a3f2b1c Add user modelpick b7e9d4f Add authentication middlewarepick c1d2e3f Add login endpointpick d4e5f6a Fix auth token expirypick e5f6a7b Update tests
# Rebase a3f2b1c..e5f6a7b onto a3f2b1c (5 commands)## Commands:# p, pick <commit> = use commit# r, reword <commit> = use commit, but edit the commit message# e, edit <commit> = use commit, but stop for amending# s, squash <commit> = use commit, but meld into previous commit# f, fixup <commit> = like "squash", but discard this commit's log message# x, exec <command> = run command (the rest of the line) using shell# b, break = stop here (continue rebase later with 'git rebase --continue')# d, drop <commit> = remove commit# l, label <label> = label current HEAD with a name# t, reset <label> = reset HEAD to a label# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]Rebase Actions
Section titled “Rebase Actions”pick — Use Commit As-Is
Section titled “pick — Use Commit As-Is”The default action. The commit is replayed onto the new base without modification.
reword — Change the Commit Message
Section titled “reword — Change the Commit Message”Stops at the commit and opens an editor with the current message for editing. The commit’s content (diff) is unchanged.
edit — Pause for Amending
Section titled “edit — Pause for Amending”Stops at the commit, allowing you to:
- Modify files (
git add/git restore) - Amend the commit (
git commit --amend) - Split the commit into multiple commits
- Continue the rebase (
git rebase --continue)
# Example workflow:# 1. Rebase opens with "edit c1d2e3f Add login endpoint"# 2. Git stops at this commit$ git log --oneline -3 # Verify you're at the right point# 3. Make changes$ echo "new code" >> src/login.c$ git add src/login.c$ git commit --amend # Amend the commit# 4. Continue$ git rebase --continuesquash — Combine with Previous Commit
Section titled “squash — Combine with Previous Commit”Melds the commit into the previous commit, combining their diffs and prompting for a new combined message:
# This is a combination of 2 commits.# This is the 1st commit message:Add authentication middleware
# This is the commit message #2:Add login endpoint
# TODO: Edit the combined messageCross-References
Section titled “Cross-References”- Merging: Alternative integration strategy to rebasing, preserving full branch history.
- Conflict Resolution: Handles merge conflicts that arise during both merging and rebasing.
- Branching: Branch creation and management fundamentals that underpin rebasing workflows.