Merge vs Rebase: When and How to Use Each in Git
In this tutorial, you'll learn about Merge vs Rebase: When and How to Use Each in Git. We cover key concepts, practical examples, and best practices.
Git merge and rebase both combine work from different branches but produce different history graphs — merge preserves chronology while rebase rewrites it.
In this tutorial, you'll learn the critical differences between Git merge and rebase — two commands that integrate changes from one branch into another. Choosing merge vs rebase shapes your commit history, affects collaboration, and can make the difference between a readable project log and an incomprehensible tangle. By the end, you'll know exactly when to use each and how to avoid the common pitfalls that trip up even experienced developers.
flowchart LR
subgraph Before
A[main: A] --> B[main: B]
A --> C[feature: C]
C --> D[feature: D]
end
subgraph After Merge
B --> E[Merge Commit]
D --> E
end
subgraph After Rebase
B --> C2[C']
C2 --> D2[D']
end
How Git Merge Works
Merge creates a special merge commit that has two parent commits. It preserves the exact timeline of both branches. This is the safest option for shared branches because it never rewrites history.
# Setup: two branches with diverging work
git checkout -b feature/payments main
echo "payment code" > payment.py
git add payment.py
git commit -m "Add payment processing"
git checkout main
echo "hotfix" >}} README.md
git add README.md
git commit -m "Fix critical typo"
# Merge feature into main
git merge feature/payments
Expected output:
Merge made by the 'ort' strategy.
payment.py | 1 +
1 file changed, 1 insertion(+)
The commit graph now shows a three-way join. The merge commit documents exactly when the integration happened.
How Git Rebase Works
Rebase rewrites your feature branch commits on top of the target branch's current tip. Instead of a merge commit, your commits appear as if they were written on top of the latest code.
git checkout feature/payments
git rebase main
Expected output:
Successfully rebased and updated refs/heads/feature/payments.
Your commits are reapplied one by one. If conflicts occur during rebase, Git pauses at each conflicting commit.
Resolving Conflicts During Rebase
When git rebase main encounters a conflict:
# Git pauses; fix the conflicting files
git add resolved_file.py
git rebase --continue
# Or skip this commit: git rebase --skip
# Or abort entirely: git rebase --abort
Expected output:
Applying: Add payment processing
Applying: Add payment validation
Merge vs Rebase Comparison
| Aspect | Merge | Rebase |
|---|---|---|
| History | Preserves exact chronology | Linearizes history |
| Merge commits | Creates one | None |
| Safety | Safe for shared branches | Rewrites history — dangerous for shared |
| Conflict resolution | One-time at merge | Per-commit during rebase |
| Traceability | Clear when integration happened | Cleaner log, less detail |
| CI/CD impact | Triggers once | Triggers on each rebased commit |
| Team convention | Standard for public branches | Used for private feature branches |
The Golden Rule
Never rebase commits that have been pushed to a shared branch. Once you push a branch and others pull it, rebasing creates divergent histories. Your teammates will see duplicate commits and Git will refuse to pull cleanly.
Common Errors
| Error | Cause | Fix |
|---|---|---|
merge conflict during rebase |
Conflicting changes on both branches | Fix each commit's conflict, git rebase --continue |
fatal: refusing to merge unrelated histories |
Two repos with no common ancestor | Use --allow-unrelated-histories |
There is no tracking information |
Branch not linked to remote | Set upstream with git branch -u |
| Divergent history after push | Rebased a shared branch | Use git push --force-with-lease (with caution) |
Already up to date |
Nothing new on target branch | Check branch names |
| Lost commits after rebase | Accidentally skipped or aborted | Use git reflog to recover |
| Merge commit in rebased branch | Rebase stopped mid-way | git rebase --abort and retry |
CONFLICT (content) repeated |
Many commits with same conflict | Squash commits first with git rebase -i |
Interactive Rebase for Clean History
Use interactive rebase to squash, reorder, or edit commits:
git rebase -i HEAD~3
An editor opens showing the last three commits. Change pick to squash to combine commits, reword to rename, or edit to split.
Practice Questions
Challenge
Create a repository with three commits on main. Branch off, add two commits. Switch back to main and add one commit. First, merge the branch and note the graph. Reset to before the merge. Now rebase the branch onto main and note how the graph changes. Compare the two histories using git log --graph --oneline. Write the full command sequence.
Real-World Task
In a team repository, you have a feature branch with six messy commits (typo fixes, debug statements, partial work). Use interactive rebase to squash them into two logical commits: "Add feature implementation" and "Add tests for feature". Then rebase onto the latest main and push. This cleanup workflow is standard at DodaTech for tools like DodaZIP where clean history helps Kubernetes-based deployments track which changes caused issues.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro