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
| 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
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
| 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.
What to Read Next
- Git Cheat Sheet — Complete Git reference
- Git Worktree: Work on Multiple Branches — Parallel development
- SSH & GPG Cheat Sheet — Secure Git operations