MeshWorld India Logo MeshWorld.
Git Version Control Rebase Merge Git Workflow Branching Collaboration Developer Tools 8 min read

Git Rebase vs Merge: When to Use Each (With Visual Guide)

Cobie
By Cobie
Git Rebase vs Merge: When to Use Each (With Visual Guide)

git rebase and git merge are the two ways to bring changes from one branch into another. One creates a clean linear history, the other preserves complete context. Choosing wrong leads to messy history, conflicts, or lost work. This guide shows you exactly when to use each.

TL;DR
  • Merge: Use for shared branches (main, develop). Preserves complete history.
  • Rebase: Use for feature branches before merging. Creates linear history.
  • Never rebase public branches that others have pulled.
  • Interactive rebase (git rebase -i) cleans up commits before sharing.
  • Golden rule: Rebase local branches, merge shared branches.

The Fundamental Difference

Merge: Preserves History

plaintext
Before:
     A---B---C feature
    /
D---E---F---G main

After `git merge feature`:
     A---B---C feature
    /         \
D---E---F---G---H main (merge commit)

Merge creates a new commit that has two parents. The branch history remains intact.

Rebase: Rewrites History

plaintext
Before:
     A---B---C feature
    /
D---E---F---G main

After `git rebase main`:
D---E---F---G---A'---B'---C' feature

Rebase replays feature branch commits on top of main. Creates linear history, but changes commit hashes.

When to Use Merge

1. Shared Integration Branches

bash
# You're on main, merging a completed feature
git checkout main
git pull origin main
git merge feature-branch
git push origin main

Use merge when integrating completed work into main, develop, or any branch others depend on.

2. Long-Running Feature Branches

bash
# Periodically sync feature branch with main
git checkout feature-branch
git merge main  # NOT rebase

If multiple developers work on the same feature branch, use merge to bring in main’s changes.

3. When You Need Complete Context

plaintext
Merge Commit H:
- Shows exactly when integration happened
- References both parent branches
- Preserves the fact that work happened in parallel

4. When History Matters for Debugging

bash
# Bisect through merge commits to find when bug was introduced
git bisect start HEAD v1.0
git bisect run ./test.sh

Merge preserves the actual timeline — crucial for git bisect.

When to Use Rebase

1. Before Merging Your Feature

bash
# Clean up your feature branch before merging
git checkout feature-branch
git fetch origin
git rebase origin/main

# Resolve any conflicts, then merge
git checkout main
git merge feature-branch  # Fast-forward, no merge commit!

2. Keeping Feature Branch Updated

bash
# While developing on feature branch
git checkout feature-branch
git fetch origin
git rebase origin/main

# Your commits are now on top of latest main

3. Cleaning Up Local Commits

bash
# Squash "WIP" commits, fix commit messages
git rebase -i HEAD~5

# Interactive rebase opens editor:
# pick abc1234 First commit
# squash def5678 WIP fix
# reword ghi9012 Another commit
# drop jkl3456 Debug code

4. When Working Alone on a Branch

bash
# No one else has your branch, rebase freely
git checkout my-private-branch
git rebase main
git push --force-with-lease  # Safe force push

Visual Workflow Comparison

Team Workflow: Merge Only

plaintext
Day 1:
main: A---B---C
             \
feature:      D---E

Day 2 (Alice merges):
main: A---B---C---F (merge commit)
             \   /
feature:      D---E

Day 3 (Bob sees):
main: A---B---C---F---G (his work)
             \   /
              D---E (preserved)

Team Workflow: Rebase + Merge

plaintext
Day 1:
main: A---B---C
             \
feature:      D---E

Day 2 (Alice rebases then merges):
feature: rebased to C---D'---E'
main: A---B---C---D'---E' (fast-forward)

Day 3 (Bob sees):
main: A---B---C---D'---E'---F
                    (linear history)

Interactive Rebase: The Power Tool

Cleaning Up Before Sharing

bash
# Start interactive rebase of last 5 commits
git rebase -i HEAD~5

Editor opens with options:

plaintext
pick 1a2b3c4 Add user authentication
pick 5d6e7f8 Fix typo in README
pick 9g0h1i2 WIP debugging
pick 3j4k5l6 Add password validation
pick 7m8n9o0 Oops forgot semicolon

Change to:

plaintext
reword 1a2b3c4 Add user authentication
fixup 5d6e7f8 Fix typo in README
drop 9g0h1i2 WIP debugging
pick 3j4k5l6 Add password validation
fixup 7m8n9o0 Oops forgot semicolon

Interactive Rebase Commands

| Command | Action | |---|---| | pick | Use commit as-is | | reword | Change commit message | | edit | Amend commit (stop to modify) | | squash | Combine with previous, keep message | | fixup | Combine with previous, discard message | | drop | Remove commit entirely | | exec | Run shell command |

Splitting a Commit

bash
git rebase -i HEAD~3
# Mark commit with 'edit'

git reset HEAD^  # Undo commit, keep changes
git add -p       # Selectively stage changes
git commit -m "First part"
git add .
git commit -m "Second part"
git rebase --continue

Handling Conflicts

Merge Conflicts

bash
git merge feature
# CONFLICT in file.txt

# Edit file to resolve
vim file.txt
git add file.txt
git commit  # Creates merge commit

Rebase Conflicts

bash
git rebase main
# CONFLICT in file.txt

# Edit file to resolve
vim file.txt
git add file.txt
git rebase --continue

# Or skip this commit
git rebase --skip

# Or abort entirely
git rebase --abort

Resolving Multiple Conflicts

bash
# Rebase with conflict autoresolution (theirs = incoming)
git rebase -X theirs main

# Or prefer ours (current)
git rebase -X ours main

The Golden Rules

Rule 1: Never Rebase Public Branches

bash
# BAD: Rebasing main that others have pulled
git checkout main
git rebase origin/main  # DON'T DO THIS!
git push --force        # BREAKS OTHERS' WORK

Rule 2: Communicate Before Force Pushing

bash
# GOOD: Safe force push after rebase
git push --force-with-lease

# This fails if someone else pushed since you last pulled

Rule 3: Use Merge for Shared, Rebase for Private

plaintext
Private Branches (rebase OK):
- feature/alice-login
- feature/bob-api-refactor
- hotfix/temp-fix

Public Branches (merge only):
- main
- develop
- release/v2.0

Common Workflows

Feature Branch Workflow

bash
# 1. Create feature branch
git checkout -b feature/login main

# 2. Do work, make commits
git add .
git commit -m "Add login form"
git commit -m "Add auth validation"
git commit -m "Add tests"

# 3. Before merging, clean up
git fetch origin
git rebase -i origin/main
# - Squash fixups
# - Reword unclear messages

# 4. Rebase onto latest main
git rebase origin/main

# 5. Merge to main (fast-forward)
git checkout main
git merge feature/login  # Clean history!

# 6. Push
git push origin main

Gitflow Workflow

bash
# Create feature branch from develop
git checkout -b feature/payment develop

# Work and commit...

# Finish feature (merge, don't rebase develop)
git checkout develop
git merge --no-ff feature/payment  # Preserves feature context

# Create release branch
git checkout -b release/v1.2 develop

# Hotfix from main
git checkout -b hotfix/security main
git commit -m "Fix security issue"
git checkout main
git merge hotfix/security
git checkout develop
git merge hotfix/security  # Merge to both!

Trunk-Based Development

bash
# Short-lived branches, rebase frequently
git checkout -b feature/short-task main

# Several times a day:
git fetch origin
git rebase origin/main

# When done, rebase and merge
git rebase origin/main
git checkout main
git merge feature/short-task

Advanced Techniques

Rebase Onto (Move Commits to Different Base)

bash
# Move commits from old-feature to main
git rebase --onto main old-feature feature-branch

# Before:
# main: A---B---C
#                  \
# old-feature:      D---E---F---G feature-branch

# After:
# main: A---B---C---D'---E'---F'---G' feature-branch

Autosquash Commits

bash
# Mark fixup commits during development
git commit -m "Add user model"
git commit -m "fixup! Add user model"  # Typo fix
git commit -m "Add controller"
git commit -m "fixup! Add user model"  # Another fix

# Later, autosquash them
git rebase -i --autosquash main
# Automatically squashes fixups!

Rebase with Exec

bash
# Run tests after each commit during rebase
git rebase -i HEAD~5 --exec "npm test"

# If tests fail, rebase stops to let you fix

Troubleshooting

Recovering From Bad Rebase

bash
# Find original state
git reflog

# Reset to before rebase
git reset --hard HEAD@{5}  # Or whatever reflog entry

Undoing a Merge

bash
# Undo merge commit (preserves changes)
git reset --soft HEAD^  # If not pushed

# Or revert (creates revert commit, safe for pushed)
git revert -m 1 HEAD  # Keep main branch changes

Finding Who Broke the Build

bash
# Use merge commits to bisect
git bisect start HEAD v1.0
git bisect run ./build.sh

# Merge commits make bisect more accurate

Summary

| Scenario | Use | Command | |---|---|---| | Integrate feature to main | Merge | git merge feature | | Update feature branch | Rebase | git rebase main | | Clean up local commits | Interactive rebase | git rebase -i HEAD~5 | | Sync shared branch | Merge | git merge main | | Fix pushed commit | Revert | git revert <commit> | | Combine commits | Squash | git rebase -i with fixup |

  • Merge: History preservation, collaboration safety
  • Rebase: Clean linear history, rewrite local work
  • Both: Use them together strategically

The right Git workflow makes your history tell a story — not a mess.