Quick Answer

A merge conflict happens when two branches change the same lines of a file and Git cannot decide which version to keep. Git marks the file with conflict markers showing your version and theirs. You resolve it by editing the file into the state you actually want, deleting the markers, staging it with git add and committing. If you would rather start over, git merge --abort restores everything to before the merge.

What a Conflict Actually Is

Git merges automatically most of the time. Two people editing different files, or different parts of the same file, merge without you noticing.

A conflict occurs only when the same lines were changed on both branches, or one branch deleted a file the other modified. Git will not guess, so it stops and asks.

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

Nothing is broken and nothing is lost. Your work is intact, their work is intact, and the repository is paused mid-merge waiting for a decision.

Check the state at any point with:

git status

It lists files under Unmerged paths — those are the ones needing your attention. Files that merged cleanly are already staged.

Reading the Conflict Markers

Git rewrites the conflicting region of the file with markers:

<<<<<<< HEAD
const greeting = "Hello";
=======
const greeting = "Hi there";
>>>>>>> feature-login

Read it as three parts:

  • Between <<<<<<< HEAD and ======= — the version on the branch you are currently on, usually yours.
  • Between ======= and >>>>>>> — the version from the branch being merged in.
  • The label after >>>>>>> — which branch or commit that side came from.

One point that confuses people during a git pull: HEAD is your local branch and the incoming side is the remote. During a rebase, however, the labels are reversed — HEAD is the upstream branch and the incoming side is your own commit being replayed. If a rebase conflict looks backwards, that is why.

You can also ask Git to show the common ancestor, which makes it much clearer who changed what:

git checkout --conflict=diff3 <file>

Resolving It Step by Step

The resolution is ordinary text editing. Produce the file you actually want.

1. Open each conflicted file and decide, for each conflict, whether you want your version, their version, both, or something new. Combining is common and perfectly valid:

// After editing — markers removed, both changes kept
const greeting = "Hi there";
const farewell = "Goodbye";

2. Delete every marker line. Leaving a <<<<<<< or ======= behind is the classic mistake and produces a syntax error. Search the file for <<<<<<< before moving on.

3. Test the result. Run the code. A merge that compiles is not necessarily a merge that works — you may have kept two halves of incompatible changes.

4. Stage and commit:

git add src/app.js
git status              # confirm nothing is still unmerged
git commit              # opens with a prepared merge message

If you want one side wholesale, Git can do it for you rather than editing by hand:

git checkout --ours src/app.js     # keep the current branch's version
git checkout --theirs src/app.js   # keep the incoming version
git add src/app.js

Use these deliberately — they discard the other side entirely for that file.

Getting Out of a Merge You Do Not Want

Nothing here is irreversible, which is worth knowing before you start experimenting.

git merge --abort

This cancels the merge and restores your branch exactly as it was. Use it whenever the conflict is larger than expected and you want to prepare properly first.

For a rebase, the equivalents are:

git rebase --abort      # cancel entirely
git rebase --continue   # after resolving the current conflict
git rebase --skip       # drop the commit being applied

If you resolved a file badly and want to start that file again:

git checkout --merge src/app.js   # restore the conflict markers

And if you have already committed a merge and want to undo it:

git reset --hard HEAD~1    # discards the merge commit AND working changes

Be careful with that last one — --hard discards uncommitted work. If you are unsure, commit or stash first. git reflog records where every branch has pointed and can recover almost anything, which is the real safety net in Git.

Preventing Conflicts

Conflicts are a workflow symptom more than a Git problem.

  • Pull frequently. Two hours of divergence conflicts far less than two weeks. Most painful conflicts are long-lived branches meeting reality.
  • Keep branches small and short-lived. A branch touching four files for two days rarely conflicts badly.
  • Communicate on shared files. Config files, route tables and dependency manifests are conflict magnets because everyone edits them.
  • Commit formatting separately. A commit that reformats a file and also changes logic conflicts with everything. Keep whitespace changes in their own commit.
  • Agree on a formatter. Prettier or Black in the project removes the whole category of conflicts caused by differing editor settings.

Two Git features worth turning on. rerere records how you resolved a conflict and replays it if the same one appears again, which is genuinely useful during long rebases:

git config --global rerere.enabled true

And a merge tool gives you a three-way visual view instead of raw markers:

git mergetool

VS Code has this built in — conflicted files show Accept Current, Accept Incoming and Accept Both buttons above each conflict, which is considerably less error-prone than deleting markers by hand.

Frequently Asked Questions

What do the merge conflict markers mean? The section between <<<<<<< HEAD and ======= is the version on your current branch. The section between ======= and >>>>>>> is the incoming version. The label after >>>>>>> names the branch it came from. All marker lines must be deleted when you resolve.
How do I cancel a merge with conflicts? Run git merge --abort, which restores your branch exactly as it was before the merge started. For a rebase the equivalent is git rebase --abort. Neither loses committed work.
Why are ours and theirs reversed during a rebase? Because rebase replays your commits on top of the other branch, so at each step HEAD is the upstream branch and the incoming change is your own commit. It is confusing but consistent once you know the direction.
Can I keep both versions in a conflict? Yes, and it is often correct. The markers are just text — edit the region into whatever the file should contain, which may include both changes, then delete the marker lines and stage the file.
How do I avoid merge conflicts? Pull frequently so branches do not diverge far, keep branches small and short-lived, avoid mixing formatting changes with logic changes, and agree on a code formatter so editor differences do not create conflicts.