Git Merge vs Rebase vs Squash: Which One Should You Use?
Three ways to integrate changes in Git. Each creates a different history. Here's when to use which.
The Scenarioβ
You have a feature branch with 3 commits, and you want to integrate it into main:
main: A --- B --- C
\
feature-branch: D --- E --- F
Three options: Merge, Rebase, or Squash
Option 1: Git Mergeβ
What It Doesβ
Creates a merge commit that combines both branches:
git checkout main
git merge feature-branch
Result:
main: A --- B --- C --------- M
\ /
feature: D --- E --- F
New commit M = Merge commit (has two parents: C and F)
Pros & Consβ
β Pros:
- Preserves complete history
- Shows when branches diverged and merged
- Safe (non-destructive)
- Clear branch context
β Cons:
- Creates extra merge commit
- History can get messy with many branches
- "Spaghetti" history in busy projects
When to Useβ
- β Merging feature branches into main
- β Team collaboration (preserves everyone's work)
- β When history matters
- β Public branches
Command:
git checkout main
git merge feature-branch
Option 2: Git Rebaseβ
What It Doesβ
Moves your commits to the tip of the target branch:
git checkout feature-branch
git rebase main
Result:
main: A --- B --- C --- D' --- E' --- F'
Your commits (D, E, F) are "replayed" on top of C
Pros & Consβ
β Pros:
- Linear history (no merge commits)
- Clean, easy to follow
- Clearer
git log - Easier to bisect
β Cons:
- Rewrites history (changes commit hashes)
- Can't use on public/shared branches
- More complex conflict resolution
- Loses branch context
When to Useβ
- β Cleaning up your feature branch before merging
- β Keeping feature branch up-to-date with main
- β Local commits (not yet pushed)
- β Never on public branches!
Command:
git checkout feature-branch
git rebase main
# Then merge (fast-forward):
git checkout main
git merge feature-branch
Option 3: Git Squash (Squash and Merge)β
What It Doesβ
Combines all feature branch commits into one, then merges:
git checkout main
git merge --squash feature-branch
git commit -m "Add feature X"
Result:
main: A --- B --- C --- S
One new commit S = All changes from D, E, F combined
Pros & Consβ
β Pros:
- Clean main branch history
- One commit per feature
- Easy to revert entire feature
- Hides messy work-in-progress commits
β Cons:
- Loses individual commit history
- Can't see development progression
- Harder to debug (big commits)
- Loses authorship of individual commits
When to Useβ
- β Feature branches with many small commits
- β When main should only have "milestone" commits
- β Hiding work-in-progress history
- β Pull requests (common on GitHub)
Command:
git checkout main
git merge --squash feature-branch
git commit -m "Add complete feature X"
Visual Comparisonβ
Mergeβ
Before:
main: A --- B --- C
\
feature: D --- E --- F
After:
main: A --- B --- C --------- M
\ /
feature: D --- E --- F
History: A β B β C β D β E β F β M
β Shows branches β
Rebaseβ
Before:
main: A --- B --- C
\
feature: D --- E --- F
After:
main: A --- B --- C --- D' --- E' --- F'
History: A β B β C β D' β E' β F'
β Linear, no branches β
Squashβ
Before:
main: A --- B --- C
\
feature: D --- E --- F
After:
main: A --- B --- C --- S
β
(D+E+F combined)
History: A β B β C β S
β Simple! β
Quick Decision Guideβ
Use Merge when:β
- Working on a team
- History matters
- Want to preserve branch context
- Merging to main/master
git checkout main
git merge feature-branch
Use Rebase when:β
- Updating your feature branch with latest main
- Cleaning up before merging
- Working alone on feature
- Want linear history
git checkout feature-branch
git rebase main
Use Squash when:β
- Feature branch has many small commits
- Want clean main branch history
- Creating pull requests
- One logical change per commit on main
git checkout main
git merge --squash feature-branch
git commit -m "Add feature"
Real-World Exampleβ
Scenario: Adding User Authenticationβ
Your feature branch commits:
1. Add User model
2. Fix typo in User model
3. Add authentication controller
4. Fix bug in auth
5. Add tests
6. Fix test typo
7. Update README
Option 1: Merge (Preserve Everything)β
git merge feature-auth
Result: All 7 commits visible in main β Complete history β Cluttered
Option 2: Rebase (Linear)β
git rebase main
Result: All 7 commits, but linear β Clean timeline β Still 7 commits
Option 3: Squash (Clean)β
git merge --squash feature-auth
git commit -m "Add user authentication with JWT"
Result: 1 commit in main β Clean! β Lost details
Common Workflowsβ
Workflow 1: GitHub Pull Request (Squash)β
# On feature branch
git add .
git commit -m "WIP: auth"
git commit -m "Fix auth"
git commit -m "Add tests"
# Push to GitHub
git push origin feature-auth
# On GitHub: Create PR β "Squash and merge"
# Result: One clean commit in main β
Workflow 2: Keep Feature Updated (Rebase)β
# Feature branch is behind main
git checkout feature-branch
git rebase main # Update with latest main
# Resolve conflicts
git rebase --continue
# Feature branch now has latest main changes β
Workflow 3: Team Collaboration (Merge)β
# Multiple developers on same feature
git checkout main
git merge feature-branch # Preserve everyone's commits
# Result: Full history of all developers β
The Golden Rulesβ
Never Rebase Public Branches!β
# β NEVER do this:
git checkout main
git rebase feature-branch
git push --force
# β
Instead, use merge:
git checkout main
git merge feature-branch
git push
Always Rebase Your Local Feature Branchβ
# β
Keep your feature up-to-date:
git checkout feature-branch
git rebase main
# Clean linear history when you merge β
Squash Before Merging to Mainβ
# Many messy commits on feature?
# β
Squash them:
git checkout main
git merge --squash feature-branch
git commit -m "Clean commit message"
Comparison Tableβ
| Aspect | Merge | Rebase | Squash |
|---|---|---|---|
| History | Non-linear | Linear | Simplified |
| Commits | All preserved | All preserved (moved) | Combined into one |
| Merge commit? | β Yes | β No | β No |
| Rewrites history? | β No | β Yes | β Yes |
| Safe for public? | β Yes | β No | β No |
| Branch context? | β Yes | β No | β No |
| Undo feature? | Hard | Hard | Easy (one commit) |
| Conflicts | Once | Per commit | Once |
| Best for | Teams | Solo/cleanup | PR/features |
Summaryβ
The Simple Versionβ
Merge = Keep everything
git merge feature # Preserves all commits + adds merge commit
Rebase = Make it linear
git rebase main # Moves your commits to tip (rewrites history)
Squash = Make it one
git merge --squash feature # Combines all commits into one
When in Doubtβ
- π€ Team project? β Use Merge
- π§Ή Cleaning up? β Use Rebase (locally)
- π¦ Pull request? β Use Squash
Remember: There's no "best" optionβonly the right option for your situation! π―
Tags: #git #version-control #merge #rebase #squash #tutorial
