The first time I hit a merge conflict, I was convinced I’d broken something. That bright red CONFLICT (content): Merge conflict in app.py message appeared, and I closed the terminal to go make coffee and calm down.
Merge conflicts are completely normal. They happen when two people edit the same piece of code in the same file, and both want to merge their changes into the main branch. Git doesn’t know whose code to keep, so it “calls for help” and asks you to resolve it manually.
What Does a Merge Conflict Look Like?
Git marks the conflicting sections with three types of markers inserted directly into the file — it looks confusing at first, but once you understand them you can read them in seconds:
<<<<<<< HEAD
def tinh_tong(a, b):
return a + b # your version
=======
def tinh_tong(a, b):
result = a + b
return result # your colleague's version
>>>>>>> feature/refactor-math
The section between <<<<<<< HEAD and ======= is your code (the current branch). The rest is code from the other branch. Your job: decide which to keep, or combine both, then delete all the markers.
Three Common Ways to Resolve Merge Conflicts
Method 1: Manual Editing in a Text Editor
The simplest approach — open the file, delete the markers, keep the correct code, then commit.
# After merge reports a conflict
git merge feature/refactor-math
# Open the conflicting file, edit manually, then:
git add app.py
git commit -m "fix: resolve merge conflict in tinh_tong function"
Pros: No extra tools needed, full control over every line of code.
Cons: Easy to miss a marker, especially in long files with many conflicts. I once pushed code and forgot to delete a >>>>>>> feature/xyz line — the build server caught it immediately, pretty embarrassing.
Method 2: Using a Merge Tool (VS Code, vimdiff, IntelliJ)
VS Code, IntelliJ, and vimdiff all do the same thing: display both versions side by side so you can choose what to keep — no more staring at a mess of markers.
# Configure VS Code as the default merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# Launch the merge tool
git mergetool
If you’re on an SSH server with no GUI, use vimdiff:
git config --global merge.tool vimdiff
git mergetool
# In vimdiff:
# ]c — jump to the next conflict
# :diffg LOCAL — keep your version
# :diffg REMOTE — keep the version from the other branch
Pros: Clear visual display, harder to miss markers, many tools offer syntax highlighting to make reading code easier.
Cons: Requires initial setup; vimdiff has a learning curve if you’re not familiar with vim.
Method 3: The ours/theirs Strategy
Sometimes you’re certain one version is always correct — for example, a config file where you just need to keep the main branch version and discard all changes from the other branch.
# Keep all code from the current branch
git checkout --ours package.json
git add package.json
# Or the opposite: keep everything from the other branch
git checkout --theirs package.json
git add package.json
Pros: Fast, no need to think too hard.
Cons: Completely discards one side’s code — use it in the wrong context and you’ll lose important changes with no way to recover them.
Analysis: When to Use Which Method?
After a few years working with Git in a team, here’s what I’ve concluded:
- Config files (package.json, requirements.txt, .env.example): Use
ours/theirs— minimal logic, just decide which version is correct. - Code files with complex logic: Must edit manually or use a merge tool — you need to understand both changes before deciding what to keep.
- Many conflicts in one file: Use a merge tool like VS Code — clearer visualization, less chance of missing a marker.
- On an SSH server: Edit manually with nano/vim or use vimdiff.
Practical Workflow: Resolving Conflicts Step by Step
This is the workflow I use whenever I hit a conflict — step by step, nothing skipped:
# Step 1: See the list of conflicting files
git status
# Conflicting files appear with "both modified" status
# Step 2: View conflict details in each file
git diff
# Step 3: Open VS Code to resolve (or edit manually)
code .
# Step 4: After fixing, mark as resolved
git add app.py
# Step 5: Check whether any conflicts remain
git status
# Step 6: Complete the merge
git commit
# Or if you're rebasing:
git rebase --continue
Before pushing, run this command to make sure no markers were left behind — it’s saved me from embarrassing build failures at least a few times:
grep -r "<<<<<<< " --include="*.py" --include="*.js" .
# No output = safe to push
Prevention: Team Habits That Reduce Conflicts
I learned this the hard way — I was so exhausted from cleaning up conflicts that I finally changed my workflow. A team of 8 adopted these 4 rules, and conflicts dropped from 3–4 times a day to 1–2 times a week:
- Pull before you start working: Always sync the latest code before writing anything new.
- Small branches, short lifespans: The longer a branch lives, the more it diverges from main, and the harder the conflicts become. I set a rule: no branch lives longer than 3 days.
- Clear task ownership: Two people shouldn’t edit the same file in the same sprint if it can be avoided.
- Merge main into your branch regularly: Sync main into your working branch every morning so conflicts stay small and manageable, instead of letting them pile up.
# Morning workflow
git checkout main
git pull origin main
git checkout feature/my-task
git rebase main
# Resolve small conflicts right here — much easier than waiting until end of sprint
Merge vs Rebase — Which Should You Choose?
The question I get asked most often. The short answer:
- Merge: Creates a merge commit, preserves the true history. Use when integrating a feature branch into main.
- Rebase: Rewrites history, keeps commits in a cleaner linear sequence. Use to update your feature branch with main before merging.
The simplest rule: never rebase a branch that multiple people are working on. Only rebase branches that you alone are working on.
Wrap-Up
Looking back at that first time I closed the terminal to make coffee — all I needed to do was open the file, delete a few marker lines, and commit. That’s really all there is to it. Master the 3 methods in this article and you won’t need a calming cup of coffee every time you see that bright red message.
In the long run, good team habits are what actually cut down on conflicts. Small branches, merge early, sync every morning — it sounds simple, but it took me nearly 6 months to do it consistently. Start with just one thing: run git rebase main before coding each morning. That alone makes a noticeable difference.

