Resolve Merge Conflicts Step by Step
Practical Git guide to resolving merge conflicts step by step — from understanding conflict markers to using merge tools and prevention tips.
Focus: resolve merge conflicts step by step
Nothing kills momentum like a git merge that ends in a wall of <<<<<<< and >>>>>>> markers. Merge conflicts are a normal part of collaborating on a codebase, but if you don't understand what Git is telling you, they can feel like a scary dead end. This lesson walks you through resolving merge conflicts step by step — from understanding the conflict markers to editing the conflicting files and committing the resolved result — so you can get back to shipping code with confidence.
The problem this lesson solves
Merge conflicts happen when two branches change the same part of the same file in different ways. Git is smart, but it can't decide which change is "correct" — that's a human decision. When you run git merge (or git pull) and Git can't automatically combine the changes, it stops and marks the file as conflicted.
The result: your working directory is frozen in a half-merged state, git status shows Unmerged paths, and you see scary markers like <<<<<<< HEAD in your files. If you don't know how to interpret those markers or how to tell Git you've resolved them, you can get stuck, or worse, accidentally commit a messy file with unresolved markers.
This lesson gives you a repeatable, step-by-step process to resolve any merge conflict — whether it's a simple one-line change or a complex conflict spanning many files.
Core concept / mental model
Think of a merge conflict like a disagreement between two teammates editing the same sentence in a document. Git has automatically merged all the parts where they agreed, but for the parts where they disagree, it leaves both versions side by side with labels so you can decide what the final text should be.
In Git terms, a conflicted file contains conflict markers:
<<<<<<< HEAD— the version from your current branch (the one you're merging into)=======— separates the two versions>>>>>>> branch-name— the version from the branch you're merging in
Your job is to edit the file, decide what the final content should be (one side, the other, or a combination), remove the markers, and then stage the resolved file and commit to complete the merge.
A key mental shift: a merge conflict is not an error. It's Git pausing to ask you a question. The merge process is designed to be resumable — you can resolve conflicts incrementally and commit when you're done.
How it works step by step
Here's the high-level flow when a merge conflict occurs:
- You run
git merge <branch>— Git attempts to combine the changes from the target branch into your current branch. - Git identifies conflicts — For files that were modified in both branches, Git tries a three-way merge using the common ancestor. If the changes overlap or are ambiguous, it marks the file as conflicted.
- Git pauses the merge — The merge is not complete. Your working directory now shows a mix of merged files (that Git combined automatically) and conflicted files (that need your input).
- You inspect the conflicts — Run
git statusto see which files are conflicted, and open those files to see the conflict markers. - You resolve each conflict — Edit the file, choose the correct final content, and remove all conflict markers.
- You stage the resolved files — Use
git add <file>to mark each conflicted file as resolved. - You commit the merge — Run
git commit(orgit merge --continue) to finalize the merge.
Pro tip: You can abort a merge at any point with
git merge --abort. This returns your working directory to the state it was in before the merge started — a useful escape hatch if you get overwhelmed or accidentally started a merge you didn't intend.
Hands-on walkthrough
Let's walk through a complete example. We'll create two branches, make conflicting changes, merge, and resolve the conflict.
Setup: create a conflict
# Initialize a repo and make an initial commit
mkdir conflict-demo
cd conflict-demo
git init
echo "Hello, world!" > greeting.txt
git add greeting.txt
git commit -m "Initial commit"
# Create a feature branch and change the file
git checkout -b feature
echo "Hello from feature!" > greeting.txt
git commit -am "Update greeting on feature"
# Go back to main and change the same file differently
git checkout main
echo "Hello from main!" > greeting.txt
git commit -am "Update greeting on main"
# Now merge the feature branch
git merge feature
You'll see output like:
Auto-merging greeting.txt
CONFLICT (content): Merge conflict in greeting.txt
Automatic merge failed; fix conflicts and then commit the result.
Inspect the conflict
git status
Output:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: greeting.txt
Now open greeting.txt — you'll see:
<<<<<<< HEAD
Hello from main!
=======
Hello from feature!
>>>>>>> feature
Resolve the conflict
Decide what the final content should be. For this example, let's say we want to combine both messages. Edit the file to:
Hello from main and feature!
Make sure you remove all conflict markers (<<<<<<<, =======, >>>>>>>).
Stage and commit
git add greeting.txt
git commit -m "Resolve merge conflict in greeting"
The merge is complete. git log will show the merge commit, and git status will be clean.
Pro tip: If you're resolving multiple conflicts in one merge, you can add them all with
git add .after you've edited all the files, but be careful — only stage files you've actually resolved.git statuswill show you exactly which files are still unmerged.
Compare options / when to choose what
There are several ways to resolve conflicts, each suited to different situations:
| Method | Best when | Pros | Cons |
|---|---|---|---|
| Manual edit | Simple conflicts, few files | Full control, no extra tools | Can be tedious for large conflicts, easy to miss markers |
Merge tool (git mergetool) |
Complex conflicts, many files | Visual diff, helps pick sides | Requires setup, has a learning curve |
| Theirs/Ours strategy | You know you want one side entirely | Fast, no manual editing | Can silently discard the other branch's changes |
| Abort + rebase | Conflict is too messy, or you want to redo the merge | Clean slate | Loses any partial resolution work |
For most cases, manual edit is the default and recommended approach. It simple, transparent, and works everywhere. For large, repetitive conflicts, tools like meld, vimdiff, or IDE integrations (VS Code's "Accept Incoming/Current Change" buttons) can save time. But tools can't think for you — you still need to understand the conflict markers to know what you're accepting.
The ours and theirs strategies (e.g., git merge -X ours, or git checkout --ours <file>) are useful when you want to force one side entirely. But they're dangerous because they ignore the other branch's changes without review — use them sparingly and only when you're sure.
Troubleshooting & edge cases
"Git says merge failed, but I don't see any conflict markers"
Sometimes Git creates a conflict for a file but the <<<<<<< markers are in a binary file or a file that's encoded in a way that hides them. Run git status to see which files Git considers conflicted. If it's a binary file, Git can't show you a text conflict — you'll need to choose one version entirely (e.g., git checkout --ours or --theirs).
"I see <<<<<<< markers everywhere after I commit"
If you commit a file that still contains conflict markers, Git will happily commit it — it doesn't check for leftover markers. This pollutes your history. To fix it:
git add <file>
git commit --amend # or make a new commit
But better to always search for conflict markers before committing. Some editors highlight them; you can also run:
grep -rn '<<<<<<<\|=======\|>>>>>>>' .
"I accidentally deleted the wrong version of a file"
If you git add a programmatically wrong file, you don't have to go back to the merge. You can use git checkout --theirs <file> or git checkout --ours <file> to restore either side, then stage again. But remember, --theirs refers to the branch you're merging from, and --ours is the current branch — keep the mental model straight.
"Merge conflicts keep happening on the same file"
This is a code smell. It usually means two people are constantly editing the same lines of a file (e.g., a generated file or a config file with frequent changes). Prevention tips:
- Keep changes small and frequent.
- Use
git pull --rebaseto avoid frequent merge commits, but be aware rebase rewrites history. - Consider splitting large files or using replace strategies for boilerplate.
What you learned & what's next
You now know how to resolve merge conflicts step by step: identify the conflict markers, decide on the correct final content, stage the file, and commit the merge. You also know how to inspect conflicts with git status, how to abort a merge, and how to prevent future conflicts.
The next lesson in this track builds on this foundation by exploring branching strategies — how to structure your branches to minimize conflicts in the first place. You'll learn about feature branching, Git flow, and trunk-based development, and how to apply the conflict-resolution skills you've just mastered to real-world team workflows.
Practice recap
Create a new repository, add two branches, and deliberately make conflicting changes to a text file. Practice resolving the conflict manually, then try using git mergetool or an IDE's conflict editor. Finally, test git merge --abort to see how to back out of a merge safely.
Common mistakes
- Committing a file that still contains conflict markers — always check for
<<<<<<<before staging. - Using
git checkout --ourson a file without understanding which branch is 'ours' — this can silently discard the other branch's work. - Running
git merge --abortafter already staging resolved files — this discards all your resolution work and restores the pre-merge state. - Editing only part of a conflict and missing the
=======divider — the file may still be syntactically invalid. - Forgetting to
git addall resolved files — Git will still consider the merge incomplete if any conflicted file isn't staged.
Variations
- Use a visual merge tool like
git mergetoolwith Meld or VS Code's built-in diff editor. - Use
git checkout --ours <file>orgit checkout --theirs <file>to quickly choose an entire file from one side. - Resolve conflicts in a rebase (
git rebaseinstead of merge) — the process is similar, but conflicts are resolved per commit, which can be cleaner.
Real-world use cases
- A developer on a shared feature branch changes the same function signature that your UI code depends on — you must decide which version to keep.
- Two team members update the same lines of a configuration file (e.g.,
.envorpackage.json) and Git can't auto-merge their changes. - Merging a long-lived release branch back into
mainafter months of parallel development, resulting in many overlapping changes.
Key takeaways
- Merge conflicts happen when two branches change the same lines of a file; Git asks you to decide the final content.
- Conflict markers (
<<<<<<<,=======,>>>>>>>) show you both versions — edit to combine or choose, then remove all markers. - The standard resolution flow is:
git statusto see conflicts, edit files,git addresolved files, thengit commit. git merge --abortlets you reset to the pre-merge state if things go wrong.- Prevent conflicts by keeping changes small, committing often, and coordinating with teammates on shared files.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.