How to Resolve Git Merge Conflicts: Fix “Automatic Merge Failed”

|

Git how to resolve merge conflicts: fix “automatic merge failed fix conflicts and then commit the result” and “this branch has conflicts that must be resolved” in Azure DevOps pull requests.

Git
9 min read
Beginner → Advanced

What Is a Merge Conflict and Why Does It Happen?

A merge conflict occurs when Git tries to combine two branches but cannot automatically decide which version of the code to keep. Git is remarkably good at merging — it can handle hundreds of files changing in parallel. But when two people edit the same lines of the same file, or when one person deletes a file that another person modified, Git stops and asks you to decide.

Understanding the three-way merge model helps: Git looks at the shared ancestor commit, your changes, and the other branch’s changes. If both sides changed the same spot, that’s a conflict.

How a conflict is born

Alice and Bob both branch off main at commit abc123. Alice changes line 14 of config.js to set timeout: 5000. Bob changes the same line to set timeout: 3000. When either one merges back into main, Git has no way to know which timeout is correct — so it flags a conflict and waits for a human to decide.

“This branch has conflicts that must be resolved” — what it means

This message appears in GitHub, GitLab, Bitbucket, and Azure DevOps pull request interfaces. It means the target branch (usually main or develop) has received commits that conflict with commits on your feature branch. The platform is blocking the merge button to protect you from data loss.

What happens to your code

Nothing is deleted or broken yet. Both versions of the conflicting code still exist in your repository. The merge is simply paused until you resolve the conflict and commit the resolution.

“Automatic merge failed; fix conflicts and then commit the result” — what Git is telling you

This is the terminal message you see after running git merge or git pull when Git encounters a conflict. Here is what it looks like in full:

Terminal output

Auto-merging src/config.js
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.

Git is telling you three things: which file(s) conflict, that it stopped without completing the merge, and exactly what to do next — fix the conflicts, then commit. Your working directory is now in a merging state, and Git has inserted conflict markers directly into the conflicting files to show you both sides.

Do not run git merge again

Once Git reports a conflict, you are already mid-merge. Running git merge again will give you an error. Resolve the conflicts, stage the files, then commit — or run git merge --abort to cancel the merge entirely.

How to Identify Conflict Markers in Your Code

When Git detects a conflict, it does something concrete: it edits the conflicting file and inserts conflict markers — special lines that clearly label “your side” and “their side.” You must read and remove these markers before the code can compile or run.

Understanding <<<<<<<, =======, and >>>>>>>

The three conflict markers divide a conflicted block into two halves:

Git merge conflict markers
  • <<<<<<< HEAD — marks the start of your changes (the branch you were on when you ran merge)
  • ======= — the dividing line between the two versions
  • >>>>>>> branch-name — marks the end of the incoming changes (the branch you are merging in)

Diff3 style — see the original too

Run git config --global merge.conflictstyle diff3 to also show the original content (the common ancestor) between the two conflict halves. This makes it much easier to understand what each side changed, not just what they ended up with.

How to find all conflicting files

After a failed conflicts merge, you have several ways to discover which files need attention:

Bash
# Method 1 — git status (fastest)
git status

# Method 2 — list only conflicted files
git diff --name-only --diff-filter=U

# Method 3 — grep for conflict markers across all files
grep -rn "<<<<<<<" .
C:\Serge\Site\articles\2026\Git merge conflicts\git status output during a conflict.jpg

How to Resolve Merge Conflicts Manually

Manual resolution is the most fundamental skill — even if you use a GUI tool, you need to understand what you are choosing. The process always follows the same three steps: edit the file, stage it, commit.

Choosing one side vs. combining changes

You have three options when you look at a conflict block:

Option A – Keep your version (HEAD)

Delete the incoming changes and all three marker lines. Leave only your code.
Git before and after (keep ours)

Option B – Accept the incoming version

Delete your changes and all three marker lines. Leave only the incoming code.

Option C – Write a combined resolution

This is the most common real-world choice. Delete all marker lines and write the correct final version yourself — often a blend of both sides, or something entirely new once you understand what each side was trying to do.
Combined resolution example
// AFTER  combined: use Alice's timeout but add Bob's comment
  timeout: 5000,  // increased for slower networks (was 3000)

Never leave conflict markers in the file

The <<<<<<<, =======, and >>>>>>> lines must all be removed from the final file. If any marker survives, your code will break — JavaScript will throw a syntax error, Python will fail to parse, and so on.

Marking conflicts as resolved with git add

Once you have edited a file and removed all conflict markers, you must explicitly tell Git the conflict is resolved. This is done with git add:

Bash
# Stage each resolved file individually
git add src/config.js
git add src/api/client.js

# Or stage everything at once
git add .

# Verify — no more "Unmerged paths" should appear
git status

Status after staging resolutions

On branch main All conflicts fixed but you are still merging. (use “git commit” to conclude merge)

Completing the merge with git commit

Once all conflicts are staged, finalize the merge with a commit. Git will pre-populate a merge commit message for you — you can accept it or customize it:

1. Run git commit

Bash
git commit
# Git opens your editor with a pre-filled message:
# Merge branch 'feature/bob-perf-fix' into main
# ...

2. Save and close the editor (or use -m)

Bash
# Or skip the editor entirely:
git commit --no-edit

3. Push the result (if working with a remote)

Bash
git push origin main

Successful merge output

[main 4f7a2c1] Merge branch ‘feature/bob-perf-fix’ into main

Pro tip

If you made a mistake resolving conflicts and want to start over, run git merge --abort at any point before committing. This returns your repository to exactly the state it was in before you started the merge.

Best Tools to Resolve Merge Conflicts

Manual text editing works, but a visual merge tool makes conflict resolution significantly faster and less error-prone — especially for large diffs. Here are the best options depending on your workflow.

Built-in: git mergetool

Git ships with a mergetool command that launches a configured merge tool for each conflicted file. You can set your preferred tool once and use it every time:

Bash
# Set VS Code as the default merge tool globally
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd \
  'code --wait $MERGED'

# Set vimdiff (no install required)
git config --global merge.tool vimdiff

# Launch the tool on all conflicted files
git mergetool

Backup files

git mergetool creates .orig backup files by default. To disable them: git config --global mergetool.keepBackup false

VS Code merge editor

VS Code has a first-class merge editor with an inline 3-way diff view. When you open a conflicted file, VS Code shows “Accept Current Change”, “Accept Incoming Change”, “Accept Both Changes”, and “Compare Changes” inline — no configuration required.

Bash
# Open the conflicted file directly in VS Code
code src/config.js

# Or use VS Code as git mergetool (see above)
# The 3-way merge editor opens automatically for .git conflicts

VS Code tip

In VS Code settings, enable Git: Merge Editor (git.mergeEditor: true) to always use the dedicated 3-panel merge editor instead of the inline view. It shows ancestor, ours, and theirs simultaneously.

IntelliJ / WebStorm

JetBrains IDEs include one of the most powerful merge editors available. The 3-pane view shows your version (left), the result (center), and the incoming version (right). You can accept individual changes with arrow buttons and edit the result pane directly.

Bash
1. VCS menu  Git  Resolve Conflicts
2. Double-click a conflicted file
3. Use << / >> arrows to accept change blocks
4. Click "Apply" when done
5. Commit via VCS  Commit (Ctrl+K)

Sublime Merge, GitKraken, and others

Sublime MergePaid / Free trial

Fast, native Git client with a clean 3-way merge interface. Conflict blocks are highlighted with accept/reject buttons. Excellent for large diffs and keyboard-driven workflows.

GitKrakenFree / Pro

Full GUI Git client with a visual conflict editor. Shows a split-diff view with checkboxes for each conflict chunk. Particularly beginner-friendly and popular in team settings.

SourcetreeFree

Full GUI Git client with a visual conflict editor. Shows a split-diff view with checkboxes for each conflict chunk. Particularly beginner-friendly and popular in team settings.

vim / Neovim + fugitiveFree

For terminal-first developers, vim-fugitive provides a :Gdiff command with a three-pane merge view. Combine with diffget //2 and diffget //3 shortcuts to accept changes block by block.
Tool3-way viewTerminalGUIFree
VS Code
IntelliJ IDEACommunity ed.
Sublime MergeTrial only
GitKrakenFree tier
vimdiff

How to Prevent Merge Conflicts in the First Place

You cannot eliminate merge conflicts entirely — they are a natural result of parallel development. But you can dramatically reduce their frequency and severity with a few disciplined habits.

Keep branches short-lived

The longer a branch lives, the more the base branch diverges from it, and the bigger the conflict when you finally merge. Aim to merge feature branches in days, not weeks.

Trunk-based development

Teams using trunk-based development merge to main multiple times per day using feature flags to hide incomplete work. This makes conflicts small and easy to resolve because each branch diverges by hours, not weeks.

Branch lifespan vs. conflict risk

1–2 days: Conflicts are rare. When they occur, they’re easy to resolve — small diffs, fresh context.
1 week: Moderate risk. Plan to update the branch before merging.
2+ weeks: High risk. Expect conflicts, and expect them to take time. Consider breaking the feature into smaller pieces.

Pull and rebase frequently

Keeping your branch up to date with the base branch means smaller gaps and smaller conflicts. Two strategies — pick one and be consistent:

Bash — Strategy 1: merge updates in
# While on your feature branch, pull in latest main
git fetch origin
git merge origin/main

# Resolve any conflicts early, while they're still small
Bash — Strategy 2: rebase onto main (cleaner history)
# Rebase your commits on top of the latest main
git fetch origin
git rebase origin/main

# If conflicts occur during rebase, resolve each commit's
# conflict one at a time, then:
git add .
git rebase --continue

# To abort the rebase and return to before:
git rebase --abort
  • Communicate with your team before editing shared files — a quick Slack message prevents half of all conflicts
  • Split large files into smaller modules — conflicts in a 50-line file are trivial; conflicts in a 2,000-line file are painful
  • Use .gitattributes to define merge strategies for generated files (e.g., lock files, compiled assets)
  • Configure CI to block merges where the branch is more than N commits behind main
  • Consider using git rerere (reuse recorded resolution) to auto-apply resolutions you’ve already made to identical conflicts
Bash — Enable git rerere
# Enable rerere globally — Git will remember your resolutions
git config --global rerere.enabled true

# After resolving a conflict once, Git will auto-resolve
# the identical conflict if it appears again (e.g., during rebase)

Frequently Asked Questions

Can I resolve GIT merge conflicts directly in GitHub or GitLab without using the terminal?

Yes. GitHub, GitLab, Bitbucket, and Azure DevOps all provide a browser-based conflict editor for simple conflicts. In GitHub, open the pull request, click “Resolve conflicts”, edit the file in the web editor, mark it as resolved, then commit the merge.

What is the difference between git merge –abort and git reset –hard?

git merge --abort safely cancels a merge that is in progress (after a conflict), returning your working directory to the exact state it was in before you ran git merge. It only works while a merge is in progress.
git reset --hard HEAD is more aggressive — it discards all uncommitted changes and moves HEAD to the specified commit. Use this only if git merge --abort is not available or does not work. Be aware that reset --hard can discard work you wanted to keep.

Why do I keep getting conflicts in package-lock.json or yarn.lock?

Lock files are auto-generated and change frequently, making them a common source of conflicts. The cleanest resolution strategy is to accept one side, then regenerate the lock file:
1. Accept either side of the conflict (delete all markers, keep one version).
2. Run npm install or yarn install to regenerate the lock file from scratch.
3. Stage and commit the regenerated lock file.
You can also add a .gitattributes entry to use the “ours” merge driver for lock files: package-lock.json merge=ours — then always regenerate after merging.

What does "deleted by us" or "deleted by them" mean in git status?

These are deletion conflicts: one side of the merge deleted a file while the other side modified it. Git cannot auto-resolve which intention wins.
To keep the file: git add <filename>
To delete the file: git rm <filename>
Then commit as normal. Make sure to communicate with the person who made the other change — deletion conflicts often signal a structural disagreement about the codebase.

Can I undo a merge after I've already committed it?

Yes. If you have not pushed yet: git reset --hard HEAD~1 removes the merge commit entirely.
If you have already pushed: use git revert -m 1 <merge-commit-hash> to create a new commit that undoes the merge without rewriting history. The -m 1 flag tells Git which parent to treat as the mainline (usually 1 = the branch you merged into).

What's the difference between resolving conflicts during a merge vs. a rebase?

The mechanics are the same — you edit files, remove conflict markers, and run git add. The key difference is the workflow after resolving:
After a merge conflict: run git commit
After a rebase conflict: run git rebase --continue
During a rebase, you may encounter conflicts for each commit being replayed, so you might resolve conflicts several times before the rebase completes. This is normal — each resolution is applied to one commit in the sequence.

How do I resolve conflicts in binary files (images, PDFs)?

Git cannot diff or merge binary files, so it always reports a conflict when both sides modify a binary file. You must choose one version explicitly:
Keep your version: git checkout --ours -- path/to/file.png
Keep the incoming version: git checkout --theirs -- path/to/file.png
Then stage and commit as usual. If the binary file genuinely needs both sides combined (unlikely), you must do that outside of Git and commit the result manually.

Also read proven strategies to follow best branching git workflow.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x