Merging & Rebasing
Combining Work
Why it matters
Eventually, branches need to come together. Understanding merge vs rebase helps you choose the right strategy and handle conflicts confidently.
Key concepts
- Merge — Combine branches, creating merge commit if needed
- Rebase — Replay commits on top of another branch
- Fast-forward — Simple pointer move when no divergence
- Merge Conflict — When same lines changed differently in both branches
The idea
Two Ways to Combine Branches
Merge (Preserve History) Like a family tree—you can see exactly when branches diverged and rejoined. Creates a “merge commit” with two parents.
main: A ─ B ─ C ─ ─ ─ M (merge commit)
↘ ↗
feature: D ─ E
Rebase (Linear History) Like rewriting history—your commits are “replayed” on top of the target branch. No merge commit. Cleaner, linear history.
Before rebase: main: A ─ B ─ C
↘
feature: D ─ E
After rebase: main: A ─ B ─ C ─ D' ─ E'
When to Use Which
| Use Merge | Use Rebase |
|---|---|
| Shared/public branches | Local/private branches |
| Want to preserve history | Want clean linear history |
| Merging feature into main | Updating feature from main |
Walkthrough
Merge Types
Fast-Forward Merge
When main hasn’t changed since you branched:
git switch main
git merge feature
# Just moves the pointer forward—no merge commit
Before: main: A ─ B
↘
feature: C ─ D
After: main: A ─ B ─ C ─ D
Three-Way Merge
When both branches have new commits:
git switch main
git merge feature
# Creates a merge commit with two parents
Rebase
# On feature branch, replay commits on top of main
git switch feature
git rebase main
# Then fast-forward main
git switch main
git merge feature
Handling Merge Conflicts
# Git pauses at conflict
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
# Open file—conflict markers show both versions
<<<<<<< HEAD
Your changes on main
=======
Their changes on feature
>>>>>>> feature
# Edit the file to resolve
# Then stage and complete
git add file.txt
git commit # Or 'git rebase --continue' for rebase
Aborting a Merge/Rebase
git merge --abort # Cancel merge, return to before
git rebase --abort # Cancel rebase, return to before
Key takeaways
- Merge preserves history; rebase linearizes it
- Fast-forward happens when target has no new commits
- Conflicts require manual resolution
- Never rebase public/shared branches
Dos & don’ts
✅ DO
- Merge for shared branches: main, develop, release branches
- Rebase for local cleanup: Before pushing, to get linear history
- Pull with rebase:
git pull --rebasekeeps history clean - Resolve conflicts carefully: Test after resolving
❌ DON’T
- Don’t rebase public branches: Others have copies—you’ll cause chaos
- Don’t force-push after rebase to shared branches: Same reason
- Don’t ignore conflicts: Resolve them properly, don’t just pick one side
Going deeper
Interactive Rebase:
git rebase -i HEAD~5 lets you edit, squash, reorder, or drop the last 5 commits.
Powerful for cleaning up messy history before sharing.
Merge Strategies:
Git has multiple merge strategies (recursive, octopus, ours, theirs).
The default ‘recursive’ handles most cases. git merge -X theirs auto-resolves conflicts in their favor.
Common mistakes
Rebasing shared branches:
If you’ve pushed commits and then rebase, you’ve rewritten public history.
Others who pulled those commits now have divergent history. Use git merge instead.
Not understanding conflict markers:
The code between <<<<<<< and ======= is yours.
The code between ======= and >>>>>>> is theirs.
Delete the markers and keep the code you want.