Fix: CONFLICT (content): Merge conflict in [file] – Automatic merge failed

The Error

You run git merge, git pull, or git rebase and Git stops with:

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

If you then run git status, you see:

On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   src/app.js

You may also see needs merge if you try to run other Git operations while conflicts are unresolved:

error: you need to resolve your current index first
src/app.js: needs merge

Why This Happens

A merge conflict occurs when Git cannot automatically combine changes from two branches. Specifically, both branches modified the same lines in the same file, and Git does not know which version to keep.

Here is a typical scenario:

  1. You create a feature branch from main.
  2. On main, someone changes line 10 of app.js.
  3. On your feature branch, you also change line 10 of app.js.
  4. You try to merge. Git sees two different edits to the same line and has no way to decide which one wins.

Git can automatically merge changes that touch different lines or different files. It only creates a conflict when the changes overlap.

Conflicts are not errors. They are Git asking you to make a decision.

How to Read Conflict Markers

When a conflict occurs, Git inserts markers into the affected file:

<<<<<<< HEAD
const port = 3000;
=======
const port = 8080;
>>>>>>> feature-branch

Here is what each section means:

  • <<<<<<< HEAD marks the start of your current branch’s version (the branch you are merging into).
  • ======= separates the two versions.
  • >>>>>>> feature-branch marks the end of the incoming branch’s version (the branch you are merging from).

Your job is to replace this entire block — including the markers — with the code you actually want.

Fix 1: Resolve Manually in Your Editor

This is the most common approach and works with any editor.

Step 1: Check which files have conflicts:

git status

Look for files listed under “Unmerged paths” marked as both modified.

Step 2: Open the conflicting file in your editor. Search for <<<<<<< to find each conflict.

Step 3: For each conflict, decide what the final code should be. You have three choices:

  • Keep your version (HEAD): Delete the incoming changes, the markers, and the separator.
  • Keep the incoming version: Delete your changes, the markers, and the separator.
  • Combine both: Write new code that incorporates both changes.

For example, if you want to keep the incoming port:

const port = 8080;

Or if you want to combine both:

const port = process.env.PORT || 8080;

Make sure no conflict markers (<<<<<<<, =======, >>>>>>>) remain in the file.

Step 4: Mark the file as resolved by staging it:

git add src/app.js

Step 5: Once all conflicts are resolved and staged, commit:

git commit

Git opens your editor with a pre-populated merge commit message. Save and close it to complete the merge.

Fix 2: Use VS Code’s Merge Conflict UI

VS Code detects conflict markers and shows an inline UI with clickable options above each conflict:

  • Accept Current Change — keeps your branch’s version (HEAD).
  • Accept Incoming Change — keeps the other branch’s version.
  • Accept Both Changes — keeps both versions, one after the other.
  • Compare Changes — opens a side-by-side diff.

To use it:

  1. Open the conflicting file in VS Code. The conflict sections are highlighted in green (current) and blue (incoming).
  2. Click the option you want above each conflict block.
  3. If the file has multiple conflicts, resolve each one.
  4. Save the file.
  5. In the terminal, stage and commit:
git add src/app.js
git commit

VS Code’s Source Control panel (the branch icon in the sidebar) also shows all conflicting files with a C badge. You can stage files directly from there.

Fix 3: Accept All of One Side (—theirs / —ours)

If you know you want to take one side’s version of an entire file, use git checkout:

To keep the incoming branch’s version (discard your changes to this file):

git checkout --theirs src/app.js
git add src/app.js

To keep your branch’s version (discard the incoming changes to this file):

git checkout --ours src/app.js
git add src/app.js

To accept one side for every conflicting file at once:

# Accept all incoming changes
git checkout --theirs .
git add .

# OR accept all of your current changes
git checkout --ours .
git add .

Caution: This discards the other side’s changes entirely for those files. Only use this when you are confident you want one version over the other.

During a rebase, --ours and --theirs are swapped. In a rebase, --ours refers to the branch you are rebasing onto (usually upstream), and --theirs refers to your commits being replayed. This is the opposite of a merge. Double-check which side you want before running the command.

Fix 4: Abort the Merge Entirely

If you are not ready to deal with conflicts and want to go back to the state before the merge:

git merge --abort

This resets your working directory and index to the state before you ran git merge. No changes are lost from either branch — the merge simply did not happen.

Use this when:

  • You merged the wrong branch by mistake.
  • You need to do prep work before attempting the merge again.
  • You want to try a different strategy (like rebasing instead).

Fix 5: Use a Merge Tool

Git can launch a visual merge tool that shows a three-way diff (base, local, remote):

git mergetool

This opens each conflicting file in your configured merge tool. Popular options include:

  • vimdiff (built-in, terminal-based)
  • meld (graphical, cross-platform)
  • kdiff3 (graphical, three-way merge)
  • Beyond Compare (commercial)
  • IntelliJ / WebStorm (built-in merge tool)

To configure your preferred tool:

git config --global merge.tool meld

After resolving all conflicts in the tool, save and close it. Git marks the files as resolved. Then commit:

git commit

Note: git mergetool creates .orig backup files by default. To disable this:

git config --global mergetool.keepBackup false

Special Cases

Conflicts During Rebase

When you run git rebase and hit a conflict, the workflow is slightly different from a merge:

CONFLICT (content): Merge conflict in src/app.js
error: could not apply abc1234... Your commit message
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
  1. Resolve the conflicts in each file (same as Fix 1 or Fix 2).
  2. Stage the resolved files:
git add src/app.js
  1. Continue the rebase (do not run git commit — the rebase handles it):
git rebase --continue
  1. If more conflicts appear on subsequent commits, repeat steps 1-3.

To abort the entire rebase and go back to your original branch state:

git rebase --abort

To skip the current commit entirely (dropping those changes):

git rebase --skip

Conflicts in Binary Files

Git cannot merge binary files (images, PDFs, compiled assets). You will see:

warning: Cannot merge binary files: logo.png (HEAD vs. feature-branch)
CONFLICT (content): Merge conflict in logo.png

There are no conflict markers to edit. You must choose one version:

# Keep the incoming version
git checkout --theirs logo.png
git add logo.png

# OR keep your current version
git checkout --ours logo.png
git add logo.png

If you need to combine the binary files (for example, overlaying two images), do it outside of Git with the appropriate tool, then git add the result.

Conflicts in package-lock.json / yarn.lock

Lock files conflict constantly, and you should never manually edit them. Instead:

For npm (package-lock.json):

# Accept either version (it doesn't matter which)
git checkout --theirs package-lock.json
# Regenerate the lock file from the merged package.json
npm install
git add package-lock.json

For yarn (yarn.lock):

git checkout --theirs yarn.lock
yarn install
git add yarn.lock

For pnpm (pnpm-lock.yaml):

git checkout --theirs pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml

The key insight: the lock file is a derived artifact of package.json. Resolve conflicts in package.json first (manually), then regenerate the lock file by running the install command. The regenerated lock file is the correct resolution.

Prevention

Merge conflicts are a normal part of collaborative development, but you can reduce their frequency:

  • Pull before you push. Run git pull (or git pull --rebase) before starting new work each day. The more in-sync you stay, the fewer conflicts you encounter.
  • Use short-lived feature branches. The longer a branch lives, the more it diverges from main, and the harder the merge. Merge feature branches within a few days, not weeks.
  • Break up large files. A 500-line file that everyone edits is a conflict magnet. Splitting it into smaller, focused modules reduces the chance that two people touch the same lines.
  • Communicate with your team. If two people are working on the same file, a quick message (“I’m refactoring the auth module this morning”) avoids painful overlapping edits.
  • Use git rerere. This built-in feature (“reuse recorded resolution”) memorizes how you resolve conflicts. If the same conflict appears again (common during repeated rebases), Git resolves it automatically. Enable it with:
git config --global rerere.enabled true

Still Not Working?

Conflict between a deleted and modified file

If one branch deleted a file and the other modified it, you see:

CONFLICT (modify/delete): src/old-module.js deleted in feature-branch
and modified in HEAD. Version HEAD of src/old-module.js left in tree.

Decide whether the file should exist:

# Keep the file (accept the modification)
git add src/old-module.js

# OR delete it (accept the deletion)
git rm src/old-module.js

Then commit.

Submodule conflicts

If a submodule pointer conflicts, you see:

CONFLICT (submodule): Merge conflict in libs/my-submodule

Check which commit each side points to:

git diff libs/my-submodule

Then set it to the commit you want:

cd libs/my-submodule
git checkout <desired-commit-hash>
cd ..
git add libs/my-submodule

Git rerere resolved it wrong

If you enabled rerere and it applied a previous resolution incorrectly:

# Undo the recorded resolution for a specific file
git checkout -m src/app.js

This re-creates the conflict markers so you can resolve the file manually again. The next resolution you commit will replace the old recorded one.

Conflict markers left in committed code

If you accidentally committed a file that still contains <<<<<<< markers, the merge is technically complete but the code is broken. Find and fix them:

# Search your project for leftover conflict markers
grep -rn "<<<<<<< " .

Edit the files to remove the markers, then create a new commit with the fix.


Related: Fix: fatal: refusing to merge unrelated histories

Related Articles