Skip to main content

03 - Git Rebase vs Merge: When to Use What

Detailed comparison between git rebase and merge: differences, advantages, disadvantages, fast-forward and when to use each strategy for optimal Git history.

What do you think about this article?

At a Glance

Detailed comparison between git rebase and merge: differences, advantages, disadvantages, fast-forward and when to use each strategy for optimal Git history.

Git Rebase vs Merge: When to Use What

One of the most discussed decisions in Git is: use rebase or merge? Both integrate changes from one branch to another, but in radically different ways. Understanding the differences, advantages, and disadvantages of each is essential to maintaining a clean Git history and collaborating effectively in teams.

🎯 What You'll Learn

  • Fundamental differences between rebase and merge
  • When to use rebase and when merge
  • Fast-forward merge vs merge commit
  • The golden rule of rebase

How Merge Works

Git merge creates a new merge commit that joins the histories of two branches. It's a non-destructive operation: the original branches are not modified.

Basic Merge
# Initial situation
main:    A---B---C
              \
feature:       D---E

# Merge feature into main
git checkout main
git merge feature

# Result
main:    A---B---C-------M
              \         /
feature:       D---E---

# M is the merge commit with two parents: C and E
Performing a Merge
# Switch to target branch
git checkout main

# Merge the feature branch
git merge feature

# Git automatically creates a merge commit
# Default message: "Merge branch 'feature' into main"

How Rebase Works

Git rebase rewrites history by moving commits from one branch onto a new base. Instead of creating a merge commit, commits are reapplied one by one onto the tip of the target branch.

Basic Rebase
# Initial situation
main:    A---B---C
              \
feature:       D---E

# Rebase feature onto main
git checkout feature
git rebase main

# Result
main:    A---B---C
                  \
feature:           D'---E'

# D' and E' are NEW commits with same content as D and E
# but different hashes (because the parent changed)
Performing a Rebase
# Switch to feature branch
git checkout feature

# Rebase onto main
git rebase main

# Feature commits are reapplied onto main
# If there are conflicts, resolve them and:
git add .
git rebase --continue

# Now you can fast-forward merge on main
git checkout main
git merge feature  # Fast-forward (no merge commit)

Fast-Forward Merge

A fast-forward merge happens when the target branch has no new commits compared to the branch being merged. Git simply "moves forward" the pointer without creating a merge commit.

Fast-Forward
# Situation after rebase
main:    A---B---C
                  \
feature:           D'---E'

# Fast-forward merge
git checkout main
git merge feature

# Result (no merge commit)
main:    A---B---C---D'---E'
                          |
feature:                  

To prevent fast-forward and force a merge commit:

git merge --no-ff feature

Key Differences

Merge:

  • Branched history: Shows when branches diverged
  • Non-destructive: Original history preserved
  • Traceable: See exactly when merge happened
  • Safe: No history rewriting
  • Creates additional merge commits

Rebase:

  • Linear history: As if you worked sequentially
  • Destructive: Rewrites commits (new hashes)
  • Clean: No noisy merge commits
  • Risky: Never rebase public branches!
  • Easier to read history

When to Use Merge

✅ Use Merge when:

  • Integrating public branches (main, develop)
  • You want to preserve history of exactly when branches diverged
  • Working in a team and others have already pulled the branch
  • You want to track milestones (completed features, releases)
  • Following Git Flow (use --no-ff to preserve structure)
Example: Team Merge
# Feature branch completed
git checkout main
git merge --no-ff feature/user-auth

# Merge commit preserves feature history
# Clear when feature was integrated
# Other developers see complete structure

When to Use Rebase

✅ Use Rebase when:

  • Working on local private branches
  • You want clean linear history
  • Updating your feature branch with latest changes from main
  • You want to avoid "noisy" merge commits
  • Before creating a Pull Request (for clean history)
Example: Keeping Feature Branch Updated
# Your feature branch is behind main
git checkout feature/payment
git rebase main

# Now your branch has latest changes from main
# Linear history, easy to review in PR

# Resolve conflicts if necessary
# git add .
# git rebase --continue

The Golden Rule of Rebase

⚠️ GOLDEN RULE

Never rebase commits that have been pushed to shared public branches!

Rebase rewrites history by changing commit hashes. If other developers have already based their work on those commits, their repository becomes inconsistent and the next pull will cause conflicts and duplications.

❌ Bad: Rebase Public Branch
# BAD! Others have already pulled main
git checkout main
git rebase feature

# This rewrites main, causing problems for everyone
✅ Good: Rebase Private Branch
# GOOD! feature is only yours, nobody pulled it
git checkout feature
git rebase main

# Update your private branch with latest changes

Recommended Workflow

Here's a workflow that combines the best of both:

Hybrid Merge + Rebase Workflow
# 1. Create feature branch from main
git checkout -b feature/new-feature main

# 2. Work on the feature
git commit -m "feat: add component"
git commit -m "feat: add tests"

# 3. Meanwhile, main has moved forward
# Update your branch with rebase (private branch, OK!)
git fetch origin
git rebase origin/main

# 4. History cleanup with interactive rebase (optional)
git rebase -i origin/main
# Squash WIP commits, fixup typos, etc.

# 5. Push feature branch
git push origin feature/new-feature

# 6. Create Pull Request on GitHub/GitLab

# 7. After code review, merge into main WITH merge commit
git checkout main
git merge --no-ff feature/new-feature

# Result: clean main history with clear milestones

Linear vs Branched History

History with Merge:

*   Merge feature B
|\
| * Feature B commit 2
| * Feature B commit 1
* | Main commit 3
* | Main commit 2
|/
* Main commit 1

Pro: See exactly when features were integrated

Con: Can become chaotic with many merges

History with Rebase:

* Feature B commit 2
* Feature B commit 1
* Main commit 3
* Main commit 2
* Main commit 1

Pro: Linear, easy to follow

Con: Lose information about when branches diverged

Conflicts: Merge vs Rebase

Both can have conflicts, but they're handled differently:

Resolving Conflicts
# Conflicts during MERGE
git merge feature
# Resolve conflicts
git add .
git commit  # Complete the merge

# Conflicts during REBASE
git rebase main
# Resolve conflicts for each conflicting commit
git add .
git rebase --continue  # Move to next commit
# Repeat until done

# Abort rebase if necessary
git rebase --abort

Team Preferences

Different teams have different preferences. Some examples:

  • Linux Kernel: Only merge (preserves complete history)
  • Rails: Rebase for feature branches, merge for important integrations
  • Google: Linear history with rebase (trunk-based development)

Conclusion

There's no universally "better" choice between merge and rebase. Merge preserves history and is safe for public branches. Rebase creates clean linear history but rewrites commits. The best strategy is often hybrid: use rebase to keep your local feature branches clean, and merge with --no-ff to integrate into public branches.

🎯 Key Points

  • Merge = non-destructive, creates merge commits, branched history
  • Rebase = rewrites history, no merge commits, linear history
  • Never rebase shared public branches
  • Use rebase for private feature branches, merge for public integrations
  • Fast-forward merge = no merge commit when possible

Frequently asked questions

What is the main difference between how Git merge and rebase integrate changes from one branch to another?

Git merge creates a new merge commit that joins the histories of two branches, while Git rebase rewrites history by moving commits from one branch onto a new base.

When does a fast-forward merge occur in Git?

A fast-forward merge happens when the target branch has no new commits compared to the branch being merged.

What is the recommended workflow for using both merge and rebase effectively?

Use rebase to keep your local feature branches clean, and merge with to integrate into public branches.

Why should you never rebase commits that have been pushed to shared public branches?

Because rebasing changes commit hashes, which can cause conflicts and duplications in other developers' repositories if they have already based their work on those commits.

Sources and further reading

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects