Merging Branches and Resolving Conflicts
Introduction
Branching lets you isolate work; merging brings that work back together. This tutorial shows you how to perform safe merges, understand different merge strategies, and confidently resolve conflicts when Git needs your help.
Prerequisites
- Comfortable with basic workflow (
add,commit,push) - Created and switched branches (see
creating-and-switching-branches.md) - Basic understanding of commit history and
git log
Learning Goals
By the end you will be able to:
- Merge feature branches into a mainline branch
- Choose between fast-forward and non–fast-forward merges
- Detect, view, and resolve merge conflicts
- Abort or restart a problematic merge
- Apply best practices to reduce conflict frequency
Mental Model of a Merge
A merge creates a new commit that has two parents (the tips of the branches you are combining) unless Git can do a fast-forward. Git performs a three-way merge using:
BASE (merge base) ← common ancestor
HEAD (current branch)
OTHER (branch being merged in)Git compares differences (BASE→HEAD) and (BASE→OTHER) and applies both sets if they don’t overlap. Overlaps become conflicts.
Fast-Forward vs Merge Commit
| Scenario | Result | When | Pros | Cons |
|---|---|---|---|---|
| Fast-forward | Pointer moves forward | Branch strictly ahead | Linear history | Loses branch boundary context |
| Merge commit | New commit with 2 parents | Histories diverged | Retains integration point | Extra commits; can become noisy |
Forcing a Merge Commit
bash
git merge --no-ff feature/loginThis records a dedicated merge commit even if fast-forward is possible (useful for grouping related changes).
Basic Merge Workflow
bash
# 1. Ensure main is current
git checkout main
git pull origin main
# 2. Merge the feature branch
git merge feature/login
# 3. Push result
git push origin mainViewing What Will Merge
bash
# Show commits that will be merged
git log --oneline main..feature/login
# Show a merge preview (no commit)
git merge --no-commit --no-ff feature/login
# If you decide not to proceed
git merge --abortTypical Conflict Scenario
Two branches edit the same lines of config/app.json.
bash
git checkout main
git merge feature/rate-limit
# Auto-merging config/app.json
# CONFLICT (content): Merge conflict in config/app.json
# Automatic merge failed; fix conflicts and commit the result.Conflict Markers
Inside the file:
<<<<<<< HEAD
"rateLimit": 200,
=======
"rateLimit": 500,
>>>>>>> feature/rate-limitResolve by choosing / combining desired value, then remove markers entirely.
Inspecting Conflicts
bash
git status # Lists unmerged paths
git diff # Shows conflict regions
git diff --name-only --diff-filter=U # Only conflicted filesAfter Editing
bash
git add config/app.json
git commit # Uses merge template messageOr supply a custom message:
bash
git commit -m "Merge feature/rate-limit into main: adjust limit to 300"Aborting a Merge
If things look wrong and you haven’t committed yet:
bash
git merge --abortReturns the working tree to the pre-merge state.
Strategies & Options
| Option | Purpose |
|---|---|
--no-ff | Force a merge commit |
--squash | Combine changes into working tree (no merge commit) |
--commit / --no-commit | Auto-commit or pause before committing |
--abort | Reset state after conflict (uncommitted) |
-X ours | Favor current branch on conflicts |
-X theirs | Favor merging branch on conflicts |
Squash Merge (Combine Changes)
bash
git checkout main
git merge --squash feature/search
git commit -m "Add search functionality"Squash keeps a cleaner main history but loses individual feature commits.
Visualizing Merges
bash
git log --graph --oneline --decorateAdvanced Conflict Tools
bash
git mergetool # Launch configured merge tool
git config merge.tool code
git config mergetool.code.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'Preventing Conflicts
- Pull / rebase frequently on long-running branches
- Keep feature branches small and focused
- Avoid formatting churn mixed with logic changes
- Align on shared file ordering / linting
- Communicate early about large refactors
Handling Binary Conflicts
For images/binaries you can’t line-merge:
bash
git checkout --ours path/to/asset.png
git checkout --theirs path/to/asset.png
git add path/to/asset.pngPick one version explicitly.
Common Pitfalls
| Problem | Cause | Fix |
|---|---|---|
| Repeated conflicts | Long-lived branch diverged | Rebase or integrate earlier |
| Huge conflict cluster | Mixed formatting + logic commits | Separate format-only commit first |
| Accidental merge commit | Auto fast-forward disabled by policy | Use git pull --ff-only or review hooks |
| Lost changes | Used checkout to discard before staging | Recover via git reflog |
Checklist Before Merging
- [ ] CI green (tests pass)
- [ ] Code reviewed (if team policy)
- [ ] Branch updated (
git fetch && git rebase origin/mainor latest merge) - [ ] No debug artifacts / secrets
- [ ] Commit messages clean
Summary
Merging integrates divergent histories. Understand the type of merge, review incoming commits, resolve conflicts surgically, and commit a clear merge snapshot. Consistent hygiene reduces friction.
Next Steps
- Explore rebase vs merge (
git-rebase-vs-merge-when-to-use-each.md) - Learn structured conflict strategies (
git-conflict-resolution-strategies.md)
Key Commands Recap
bash
git merge <branch>
git merge --no-ff <branch>
git merge --squash <branch>
git merge --abort
git diff --name-only --diff-filter=U
git log --graph --oneline --decorate