Merge conflicts happen when Git can't automatically combine changes from two branches. They're a normal part of collaboration — not something to fear.
Why Conflicts Happen
A conflict occurs when two branches modify the same lines in the same file. Git doesn't know which version to keep, so it asks you to decide.
Common scenarios:
- Two developers edit the same function
- One developer renames a variable while another modifies the same line
- A file is deleted on one branch and modified on another
Conflicts do not happen when:
- Two branches edit different files
- Two branches edit different parts of the same file
What a Conflict Looks Like
When you run git merge or git pull and there's a conflict, Git marks the file with conflict markers:
function getUser(id) {
<<<<<<< HEAD
return db.users.findById(id);
=======
return db.users.findOne({ _id: id });
>>>>>>> feature/update-db
}<<<<<<< HEAD— your current branch's version=======— the divider between the two versions>>>>>>> feature/update-db— the incoming branch's version
Resolving Conflicts Step by Step
- Identify conflicted files:
git status
# Look for "both modified" files-
Open the file and find the conflict markers.
-
Choose the correct code. Remove the conflict markers and keep the version you want — or combine both:
function getUser(id) {
return db.users.findOne({ _id: id });
}- Stage the resolved file:
git add src/user.js- Commit the merge:
git commit -m "Resolve merge conflict in user query method"Resolving Conflicts During Rebase
Conflicts during rebase work differently. Git pauses at each conflicting commit:
git rebase main
# CONFLICT in src/user.js
# Fix the conflict, then:
git add src/user.js
git rebase --continueIf things go wrong and you want to start over:
git rebase --abortUsing a Merge Tool
Visual merge tools make conflicts easier to understand:
# Open the default merge tool
git mergetool
# Configure VS Code as your merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'VS Code has excellent built-in conflict resolution — it shows "Accept Current", "Accept Incoming", "Accept Both", and "Compare Changes" buttons above each conflict.
Accepting One Side Entirely
When you know one branch should win completely:
# Keep your version for all conflicts
git checkout --ours src/user.js
git add src/user.js
# Keep the incoming version for all conflicts
git checkout --theirs src/user.js
git add src/user.jsFor an entire merge:
# Accept all of ours
git merge feature/update-db --strategy-option ours
# Accept all of theirs
git merge feature/update-db --strategy-option theirsPrevention Strategies
The best conflict is one that never happens:
- Pull frequently. Merge
maininto your branch daily to catch conflicts early when they're small. - Keep branches short-lived. The longer a branch lives, the more it diverges.
- Communicate with your team. If two people need to edit the same file, coordinate.
- Break up large files. A 500-line file creates more conflicts than five 100-line files.
- Use consistent formatting. Auto-formatters like Prettier prevent whitespace-only conflicts. Configure them to run on save or as a pre-commit hook.
# Example: run Prettier as a pre-commit check
npx lint-staged- Use lock files correctly. For
package-lock.jsonorpnpm-lock.yamlconflicts, don't resolve manually — regenerate:
# Delete the conflicted lock file, reinstall, and stage
rm pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml