M
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)

Vishnu
By Vishnu

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.

:::note[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

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

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

# 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

# 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

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

# 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

# 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

# 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

# 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

# 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

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

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

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

Editor opens with options:

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:

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

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

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

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

# 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

# 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

# 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

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

# 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

# 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

# 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)

# 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

# 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

# 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

# Find original state
git reflog

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

Undoing a Merge

# 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

# 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.