Git Rebase
Rebasing is the process of moving or "replaying" commits from one branch onto a different base point. The result is a clean, linear commit history as if the feature branch was created from the latest commit on main — even if it was created much earlier.
Real-life analogy: Imagine writing an essay based on a textbook edition from last year. Before submitting it, there is a newer edition of the textbook. Rebasing is like rewriting the essay as if it was always based on the new edition — making the essay current and relevant, with no reference to the old edition.
Merge vs Rebase
Both merge and rebase combine changes from branches, but they produce different histories:
After Merging:
main: A ──── B ──── C ──────────── M (merge commit)
\ /
feature: D ──── E ──
Merge keeps the full history of when branches diverged and converged. A merge commit is created.
After Rebasing:
main: A ──── B ──── C ──── D' ──── E'
Rebase replays the feature commits (D, E) on top of main's latest commit (C), creating new commits D' and E'. The history appears linear — as if the feature was always developed after C.
Basic Rebase
# On the feature branch:
git switch feature-login
# Rebase onto the latest main:
git rebase main
Git will take each commit on feature-login that is not in main and replay them one by one on top of main's latest commit.
Step-by-Step Rebase Example
# Starting point:
# main: A ──── B ──── C
# feature: A ──── B ──── D ──── E
# Step 1: Switch to the feature branch
git switch feature-login
# Step 2: Rebase onto main
git rebase main
# Git output:
Successfully rebased and updated refs/heads/feature-login.
# Result:
# main: A ──── B ──── C
# feature: A ──── B ──── C ──── D' ──── E'
Now the feature branch is "on top of" the latest main, making it much easier to merge cleanly.
After Rebasing — Fast-Forward Merge
After rebasing the feature branch onto main, switching to main and merging results in a perfect fast-forward (no merge commit needed):
git switch main
git merge feature-login
# Output: Fast-forward
Resolving Conflicts During Rebase
If a conflict occurs while replaying a commit, Git pauses the rebase:
CONFLICT (content): Merge conflict in index.html
error: could not apply d4e5f6g... Add login form
hint: Resolve all conflicts manually, then run "git rebase --continue"
Resolve the conflict in the file, then:
# Stage the resolved file
git add index.html
# Continue the rebase to the next commit
git rebase --continue
If the rebase needs to be cancelled entirely and the branch returned to its original state:
git rebase --abortInteractive Rebase — Rewriting History
Interactive rebase (git rebase -i) is one of Git's most powerful features. It allows editing, reordering, squashing, or deleting commits before they are applied.
# Interactively rebase the last 3 commits
git rebase -i HEAD~3
This opens a text editor showing the last 3 commits:
pick a3f92b1 Add login form HTML
pick b7c3d45 Fix typo in login form
pick c1a2b3c Add login form CSS
Interactive Rebase Commands
| Command | Action |
|---|---|
pick | Keep the commit as-is |
reword | Keep the commit but edit its message |
edit | Pause rebase to amend the commit |
squash | Combine this commit with the previous one |
fixup | Like squash but discards the commit message |
drop | Delete the commit entirely |
reorder | Change the line order to reorder commits |
Squash Example: Combining 3 Commits into 1
Change the editor to:
pick a3f92b1 Add login form HTML
squash b7c3d45 Fix typo in login form
squash c1a2b3c Add login form CSS
Save and close. Git opens another editor to write the combined commit message.
The Golden Rule of Rebase
Never rebase commits that have already been pushed to a shared remote branch.
Rebasing rewrites commit history (creates new commit IDs). If others have already based their work on the original commits, rebasing will cause major confusion and conflicts for the team.
Rebase is safe to use on:
- Local branches that have not been pushed
- Personal branches that only one person is working on
- Feature branches before opening a Pull Request
Summary
Rebase moves branch commits onto a new base point, creating a clean linear history. It is ideal for keeping feature branches up to date with main before merging. Interactive rebase (-i) is powerful for cleaning up commits — squashing, reordering, or editing them. Never rebase commits that have already been shared on a remote branch.
