Git Merge vs Rebase: Complete Guide with When to Use Each

Understanding the Fundamental Difference

Merge and rebase are two different ways to integrate changes from one branch into another in Git. Understanding when to use each is crucial for maintaining a clean, understandable project history.

Why does this matter? The choice between merge and rebase affects your project's commit history, collaboration workflow, and even your ability to debug issues. A poor choice can lead to confusing history, difficult rollbacks, or collaboration problems.

Simple Analogy: Think of merge and rebase like two different ways of writing a collaborative story. Merge is like having two authors write separate chapters, then combining them into one book with a note saying "these chapters were written separately." Rebase is like rewriting one author's chapters to fit seamlessly into the other author's timeline, as if they were all written in sequence by a single author.

Visual Comparison: How Merge and Rebase Work

Initial State (Before Integration)

main
A
B
C
feature
D
E

Feature branch was created from commit C. Both branches have diverged.

After Git Merge

A
B
C
M
D
E

What happens: Git creates a new merge commit (M) that has two parents: C (from main) and E (from feature). The history shows the divergence and convergence.

Visual result: A branch-and-merge pattern in the commit history.

After Git Rebase

A
B
C
D'
E'

What happens: Git moves the entire feature branch to begin on top of the latest main commit. Commits D and E are recreated as D' and E' (new commit hashes).

Visual result: A straight, linear history as if the feature was developed sequentially.

Detailed Explanation: How Git Merge Works

Merge is Git's way of combining two separate lines of development. When you merge, Git finds a common ancestor commit and creates a new commit that combines changes from both branches.

The Three-Way Merge Process

When Git performs a merge (specifically a three-way merge), it:

  1. Finds the common ancestor: The last commit that both branches share
  2. Compares changes: Sees what changed in each branch since the ancestor
  3. Combines changes: Attempts to automatically combine non-conflicting changes
  4. Creates merge commit: Makes a new commit with two parents (unless it's a fast-forward)
# Basic merge command
git checkout main
git merge feature-branch

# With no-fast-forward option (always creates merge commit)
git merge --no-ff feature-branch

# What happens internally:
# 1. Git finds common ancestor of main and feature-branch
# 2. Creates new commit M with changes from both branches
# 3. Commit M has two parents: main's tip and feature's tip

Real-World Merge Example

Let's say you're working on a feature while your teammate fixes a bug:

# Starting point: You're on feature/add-search
git checkout feature/add-search

# You've made commits D and E on your feature
git log --oneline --graph
# * e5f2a1d (HEAD -> feature/add-search) Add search results display
# * a8b3c2d Add search input field
# * c1d2e3f (main) Initial commit

# Meanwhile, teammate fixed a bug on main
git checkout main
git log --oneline --graph
# * f4g5h6i Fix login bug
# * c1d2e3f Initial commit

# You want to integrate your feature with the bug fix
git merge feature/add-search

# Result: New merge commit M with parents f4g5h6i and e5f2a1d
git log --oneline --graph
# * m7n8o9p (HEAD -> main) Merge branch 'feature/add-search'
# |\
# | * e5f2a1d Add search results display
# | * a8b3c2d Add search input field
# * | f4g5h6i Fix login bug
# |/
# * c1d2e3f Initial commit

What you see: The graph shows the branch divergence and merge. The history preserves exactly what happened: you developed a feature while someone else fixed a bug, then you merged them together.

Detailed Explanation: How Git Rebase Works

Rebase is Git's way of moving a branch to a new base commit. Instead of creating a merge commit, it rewrites history by creating new commits for each original commit in the branch.

The Rebase Process Step by Step

When Git performs a rebase, it:

  1. Saves your commits: Temporarily saves the commits from your branch
  2. Resets to new base: Moves your branch pointer to the target commit
  3. Reapplies commits: Replays your saved commits one by one on top of the new base
  4. Creates new commits: Each replayed commit gets a new hash (they're different commits)
# Basic rebase command
git checkout feature-branch
git rebase main

# Interactive rebase (for cleaning up commits)
git rebase -i main

# What happens internally:
# 1. Git saves commits from feature-branch (temporarily)
# 2. Resets feature-branch to point to main's tip
# 3. Replays saved commits on top, creating new commits D' and E'
# 4. Original commits D and E become orphaned (eventually garbage collected)

Real-World Rebase Example

Using the same scenario as before, but with rebase:

# Starting point: You're on feature/add-search
git checkout feature/add-search

# Your commits D and E exist on feature branch
git log --oneline --graph
# * e5f2a1d (HEAD -> feature/add-search) Add search results display
# * a8b3c2d Add search input field
# * c1d2e3f (main) Initial commit

# Teammate's bug fix is on main
git checkout main
git log --oneline
# f4g5h6i Fix login bug
# c1d2e3f Initial commit

# You rebase your feature onto updated main
git checkout feature/add-search
git rebase main

# Result: Your commits are now on top of the bug fix
git log --oneline --graph
# * j1k2l3m (HEAD -> feature/add-search) Add search results display
# * n4o5p6q Add search input field
# * f4g5h6i (main) Fix login bug
# * c1d2e3f Initial commit

# Now you can do a fast-forward merge to main
git checkout main
git merge feature/add-search
# This is a fast-forward (no merge commit needed)

Important observation: Notice the commit hashes changed! e5f2a1d became j1k2l3m, and a8b3c2d became n4o5p6q. These are different commits with the same changes applied on top of different base code.

Key Differences: Merge vs Rebase

Git Merge

  • Preserves history: Shows exactly what happened
  • Non-destructive: Doesn't rewrite commit history
  • Creates merge commits: Results in branch/merge pattern
  • Safe for shared branches: Others won't be affected
  • Shows collaboration: Clear when parallel work happened
  • Easier for beginners: More straightforward to understand

Git Rebase

  • Linear history: Creates straight timeline
  • Rewrites history: Changes commit hashes
  • Avoids merge commits: Results in cleaner log
  • Dangerous when shared: Can cause issues for others
  • Hides parallel work: Looks like sequential development
  • Advanced technique: Requires more understanding

When to Use Merge vs Rebase

๐Ÿ“š

Use Merge When:

  • Merging to shared branches (main, develop)
  • Preserving exact history is important
  • Working with beginners on the team
  • You need to easily revert the merge
๐Ÿงน

Use Rebase When:

  • Cleaning up local feature branch history
  • Preparing feature for review/merge
  • You want linear history for readability
  • You're the only one working on the branch
โš ๏ธ

Never Rebase:

  • Public/shared branches
  • Branches others are working on
  • When you've already pushed the branch
  • If you're not comfortable with the risks

Practical Workflow Examples

Scenario 1: Feature Development (Recommended Workflow)

# === RECOMMENDED: Rebase locally, merge to shared ===

# 1. Start feature from updated main
git checkout main
git pull
git checkout -b feature/new-ui

# 2. Develop with frequent commits
git add .
git commit -m "WIP: Start new UI component"
git commit -m "WIP: Add styling"
git commit -m "WIP: Fix responsive issues"

# 3. Clean up commits before sharing
git rebase -i main
# In interactive editor: squash WIP commits, rewrite messages

# 4. Update with latest main (using rebase)
git checkout main
git pull
git checkout feature/new-ui
git rebase main

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

# 6. Create pull request, get review
# 7. Merge to main (with merge commit for history)
git checkout main
git merge --no-ff feature/new-ui
git push

Scenario 2: Collaborative Feature Branch

# === COLLABORATIVE: Use merge, not rebase ===

# Situation: You and a teammate are working on same feature branch

# 1. Teammate pushes their changes
git checkout feature/collaborative
git add .
git commit -m "Teammate's changes"
git push

# 2. You want to get their changes
# DO NOT REBASE! (would rewrite shared history)
git pull origin feature/collaborative
# This does: git fetch + git merge

# 3. Now you have their changes merged with yours
# 4. Continue working, push when ready
git add .
git commit -m "My additional changes"
git push

Interactive Rebase: Cleaning Up Your History

One of the most powerful uses of rebase is cleaning up commit history before sharing your work.

# Start interactive rebase for last 4 commits
git rebase -i HEAD~4

# Editor opens with something like:
pick a1b2c3d Add login button
pick b2c3d4e Fix typo in button
pick c3d4e5f Add hover effect
pick d4e5f6g Remove console.log

# You can change to:
pick a1b2c3d Add login button
squash b2c3d4e Fix typo in button
fixup c3d4e5f Add hover effect
fixup d4e5f6g Remove console.log

# Result: One clean commit "Add login button with hover effect"
# Instead of four messy commits

Interactive rebase commands:

  • pick - use the commit
  • reword - use commit but edit message
  • edit - use commit but stop for amending
  • squash - combine with previous commit
  • fixup - like squash but discard message
  • drop - remove the commit

Golden Rules of Rebasing

Rule 1: Never rebase public/shared branches
If others are using the branch, rebasing will force them to deal with conflicts and rewritten history. This is the most important rule!

Rule 2: Rebase locally before pushing
Use rebase to clean up your local commits before sharing them. Once pushed, assume the history is public and shouldn't be rewritten.

Rule 3: Use rebase to update feature branches
Instead of merging main into your feature branch, rebase your feature onto main. This keeps history linear and avoids "merge commits in feature branches."

Rule 4: Understand you're rewriting history
Rebasing creates new commits with new hashes. Any references to old commit hashes (in CI systems, comments, etc.) will break.

Which operation should you NEVER do on a branch that has been pushed and others are using?
  • git rebase
  • git merge
  • git pull
  • git fetch

Frequently Asked Questions

Which is better: merge or rebase?

Neither is universally better - they serve different purposes and have different trade-offs:

Merge is better when:

  • You want to preserve the exact historical record
  • You're working on shared/public branches
  • You need the safety of non-destructive operations
  • Your team includes beginners or prefers simplicity
  • You need to easily revert the integration

Rebase is better when:

  • You want a clean, linear history for readability
  • You're cleaning up local commits before sharing
  • You want to avoid "merge commits in feature branches"
  • You're the only person working on the branch
  • You need to resolve conflicts in small, manageable pieces

Most teams use a hybrid approach: Rebase locally for cleanup, then merge to shared branches with --no-ff to preserve feature context.

What happens if I accidentally rebase a shared branch?

If you've already pushed the rebased branch, you have a problem. Here's how to handle it:

If NO ONE has pulled yet:

# Force push to overwrite remote (DANGEROUS!)
git push --force-with-lease origin branch-name

# Warn teammates immediately!

If others HAVE pulled:

  1. Apologize to your teammates (seriously)
  2. Ask everyone to stop work on that branch
  3. Revert to the pre-rebase state:
    git reflog
    git reset --hard HEAD@{1}
    git push --force origin branch-name
  4. Have everyone delete their local copy and re-clone/fetch

Prevention is better: Use --force-with-lease instead of --force as it checks if you're overwriting someone else's work. Better yet, follow the golden rule: never rebase shared branches.

How do I update my feature branch with latest main changes?

You have two options, each with different implications:

Option 1: Merge main into feature (safer)

# On your feature branch
git checkout feature/my-feature
git merge main

# Pros: Simple, preserves history, safe
# Cons: Creates merge commit in feature branch

Option 2: Rebase feature onto main (cleaner)

# On your feature branch
git checkout feature/my-feature
git rebase main

# Pros: Linear history, no merge commits
# Cons: Rewrites history, more complex conflicts

Which to choose?

  • If you haven't pushed the feature branch yet โ†’ rebase
  • If you've pushed but you're the only one working on it โ†’ rebase, then force push
  • If others are using the branch โ†’ merge
  • If you want simplest/safest approach โ†’ merge
  • If you want cleanest history โ†’ rebase
What's the difference between squash merge and rebase?

Both can create a single commit from multiple commits, but they work differently:

Squash merge:

# On main branch
git merge --squash feature-branch
git commit -m "Combined feature"

# Result: One new commit on main with all changes
# Original feature branch commits remain unchanged
# Feature branch history is preserved separately

Rebase with squash:

# On feature branch
git rebase -i main
# Mark commits as "squash" in interactive editor

# Result: Feature branch commits are combined
# Then you can fast-forward merge to main

Key differences:

  • Squash merge happens during the merge to main
  • Rebase squash happens on the feature branch before merging
  • Squash merge keeps feature branch history intact
  • Rebase squash rewrites feature branch history
  • Squash merge is simpler and safer for shared branches
  • Rebase squash gives more control over the final commit

Recommendation: Use squash merge for simple cleanup. Use interactive rebase when you need fine-grained control over combining commits.

How do I resolve conflicts during rebase vs during merge?

Conflict resolution works similarly for both, but the context is different:

During merge:

# Git detects conflicts during merge
git merge feature
# CONFLICT (content): Merge conflict in file.txt

# Resolve conflicts in all files at once
vim file.txt # Fix conflicts
git add file.txt
git commit # Creates merge commit

During rebase:

# Git stops at each conflicting commit during rebase
git rebase main
# CONFLICT (content): Merge conflict in file.txt
# Could not apply abc1234... Commit message

# Resolve conflicts for THIS commit only
vim file.txt # Fix conflicts
git add file.txt
git rebase --continue
# Rebase continues to next commit, may have more conflicts

Key differences:

  • Merge: One conflict resolution for all changes
  • Rebase: May need to resolve same file multiple times (once per conflicting commit)
  • Merge creates one merge commit with all resolutions
  • Rebase applies resolutions to individual replayed commits
  • Rebase can be more work but results in cleaner individual commits

Pro tip: If rebase has many conflicts, consider using git rebase --abort and doing a merge instead, or using git merge first to resolve bulk conflicts, then rebase.

Should our team standardize on merge or rebase?

Most successful teams use a hybrid approach rather than standardizing on one or the other. Here's a common team agreement:

Team Agreement Example:

# Our Team's Git Workflow Agreement

# 1. For local feature branches:
# - Use rebase to clean up commits before pushing
# - Use rebase to update with main changes

# 2. For shared feature branches (collaboration):
# - Use merge, not rebase
# - Coordinate with teammates

# 3. For merging to main/develop:
# - Always use merge --no-ff
# - Creates merge commit for feature context

# 4. NEVER rebase:
# - main or develop branches
# - Any branch that has been pushed and others use

# 5. Communication:
# - Document in PR description if you rebased
# - Warn before force-pushing
# - Help teammates who are learning

Key principles for team standardization:

  • Choose what fits your team's experience level
  • Document the agreed workflow
  • Provide training for everyone
  • Use Git hooks or CI to enforce rules if needed
  • Review and adjust the workflow periodically

Remember: Consistency within the team is more important than which approach you choose. A consistent, understood workflow is better than a "perfect" but inconsistently applied one.

Previous: Creating and Merging Branches Next: Conflict Resolution