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

CommandAction
pickUse commit as-is
rewordChange commit message
editAmend commit (stop to modify)
squashCombine with previous, keep message
fixupCombine with previous, discard message
dropRemove commit entirely
execRun 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

ScenarioUseCommand
Integrate feature to mainMergegit merge feature
Update feature branchRebasegit rebase main
Clean up local commitsInteractive rebasegit rebase -i HEAD~5
Sync shared branchMergegit merge main
Fix pushed commitRevertgit revert <commit>
Combine commitsSquashgit 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.