LearnDevOpsHands-On Labs
Troubleshooting Matrix/CONFLICT (content): Merge conflict in file
GitHigh Severity

CONFLICT (content): Merge conflict in file

Fix a Git merge conflict: run git status, edit the conflict markers, git add the file, then git commit. Use git merge --abort to start over, or checkout --ours.

Observed Error Signature / Log Pattern
Auto-merging src/config.ts

Incident Overview

Fix a Git merge conflict: run git status, edit the conflict markers, git add the file, then git commit. Use git merge --abort to start over, or checkout --ours.

medium fix·6 min read

By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026

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

CONFLICT (modify/delete): src/old.ts deleted in HEAD and modified in feature/new. Version feature/new of src/old.ts left in tree.

error: could not apply a1b2c3d... Add retry logic

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

• List exactly which files are conflicted

This is the authoritative list, and it is shorter than git status. Anything not listed merged cleanly and does not need your attention.

• See both sides plus the common ancestor

diff3 style adds the original version between the two sides, which usually makes it obvious which side changed what. Without it you see two versions and have to guess what the base was.

• If the resolution is going badly, get back to where you started

This restores the pre-merge state completely. Use git rebase --abort during a rebase, and git cherry-pick --abort during a cherry-pick. Nothing is lost.

Both branches changed the same lines in the same file, so Git cannot decide which version is correct. It marks the file, stops, and waits for you.

This is normal. It is not a failure state.

BASHDiagnostic / remediation command
git diff --name-only --diff-filter=U

Find the conflicted files

--diff-filter=U means unmerged, and this is the authoritative list. git status shows it too, buried among other information.

BASHDiagnostic / remediation command
git diff --name-only --diff-filter=U

Read the markers

Between <<<<<<< and ======= is your current branch. Between ======= and >>>>>>> is what you are merging in. The labels tell you which is which, and they matter during a rebase where the sides are swapped from what you might expect.

Add the common ancestor, which usually makes the decision obvious:

Now you can see the base was 10000: one side lowered it, the other raised it. Without the ancestor you are guessing which side actually changed.

Make it the default:

zdiff3 is the improved version, which also removes lines common to both sides from the conflict region, leaving a smaller thing to read.

BASHDiagnostic / remediation command
<<<<<<< HEAD
const TIMEOUT = 5000
=======
const TIMEOUT = 30000
>>>>>>> feature/retry

Resolve

Edit the file, remove all three marker lines, keep what is correct. It is frequently neither side verbatim.

Staging a conflicted file is how you tell Git it is resolved. Repeat for each file, then:

Before committing, check you did not leave a marker behind:

Committed conflict markers are a genuinely common and embarrassing mistake, and a CI grep for them is worth adding.

BASHDiagnostic / remediation command
git add src/config.ts

Taking one side wholesale

When one side is simply correct, for a lockfile or generated output:

During a rebase, --ours and --theirs are reversed from what you expect. A rebase replays your commits on top of the upstream branch, so the upstream is checked out and becomes "ours", while your commit being replayed is "theirs". This catches almost everyone once.

For a lockfile the better answer is usually to regenerate it rather than pick a side:

BASHDiagnostic / remediation command
git checkout --ours package-lock.json      # current branch
git checkout --theirs package-lock.json    # incoming branch
git add package-lock.json

Other conflict types

There are no markers because there is no content to interleave. Decide:

add/add. Both branches created the same path independently. Resolved like a content conflict.

rename/rename. Both renamed the same file differently. Git leaves all the variants in the tree; pick one and git rm the rest.

BASHDiagnostic / remediation command
CONFLICT (modify/delete): src/old.ts deleted in HEAD and modified in feature/new.

Abort

Each restores the state before the operation started. Nothing is lost, and there is no reason to hesitate: a half-finished merge you no longer understand is worth abandoning and restarting with a clearer head.

git merge --abort fails if you had uncommitted changes when you started the merge, which is the argument for a clean working tree before merging.

BASHDiagnostic / remediation command
git merge --abort
git rebase --abort
git cherry-pick --abort

Reducing how often this happens

Merge the target branch into yours regularly. A feature branch that tracks main weekly resolves conflicts in small pieces rather than one enormous one at the end.

Turn on rerere. Git records how you resolved a conflict and replays it automatically next time it sees the same one:

This pays for itself during a long rebase where the same conflict reappears in commit after commit.

Use a merge tool for large conflicts:

VS Code, IntelliJ and the rest all have three-way merge editors, and for a conflict spanning many hunks they are considerably faster than editing markers by hand.

BASHDiagnostic / remediation command
git config --global rerere.enabled true

A checklist

Frequently Asked Questions

What do the conflict markers mean?

<<<<<<< to ======= is the version on your current branch, and ======= to >>>>>>> is the incoming version, with the branch names on the marker lines. With merge.conflictStyle set to diff3 or zdiff3 you also get the common ancestor between ||||||| and =======, which is much more useful because it shows what both sides started from. Seeing the base usually makes it immediately clear which side made the meaningful change, rather than leaving you to guess from two similar-looking versions.

Why are --ours and --theirs backwards during a rebase?

Because a rebase works by checking out the upstream branch and replaying your commits on top of it, one at a time. From Git's point of view the checked-out upstream is "ours" and the commit being applied, which is yours, is "theirs". It is the opposite of a merge, where your branch is checked out and the incoming one is theirs. The reliable habit is to read the branch names on the conflict marker lines rather than relying on which flag feels right.

How do I undo a merge that is going badly?

git merge --abort restores the state exactly as it was before the merge began, and the equivalents are git rebase --abort and git cherry-pick --abort. Nothing is lost and there is no penalty for using them, so abandoning a confusing resolution and starting again is often the fastest path. The one limitation is that git merge --abort can fail if you had uncommitted changes when you started, which is a good reason to begin any merge with a clean working tree.

What should I do with a conflicted lockfile?

Regenerate it rather than resolving it by hand. A package-lock.json or yarn.lock is generated output, and hand-merging two versions reliably produces something that does not correspond to any real dependency resolution. Take either side with git checkout --theirs package-lock.json, then run npm install to regenerate it from the merged package.json, and stage the result. The same logic applies to any generated file: resolve the source, then regenerate.

How can I avoid resolving the same conflict repeatedly?

Enable rerere with git config --global rerere.enabled true. Git records your resolution of each conflict and replays it automatically whenever it encounters an identical one, which is exactly what happens during a long rebase where the same hunk conflicts in commit after commit. The broader habit that helps more is merging the target branch into your feature branch regularly, so conflicts arrive in small, comprehensible pieces instead of as one large one at the end.

Reference and practice

Learn the underlying concept

Other Git errors

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Get notified about new tutorials and features.

• Roadmaps

• Interview Prep

• Certifications

• Company

© 2026 DevOpsLesson. All rights reserved.

Need to practice this scenario?

Simulate this error condition and practice recovery commands safely in our in-browser terminal.

Open Git Sandbox