Skip to main content

Git Merge vs Rebase vs Squash: Which One Should You Use?

Β· 6 min read
Mahmut Salman
Software Developer

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​

AspectMergeRebaseSquash
HistoryNon-linearLinearSimplified
CommitsAll preservedAll 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?HardHardEasy (one commit)
ConflictsOncePer commitOnce
Best forTeamsSolo/cleanupPR/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