Merge Conflicts

Table of Contents

  1. What a Conflict Is (and Isn't)
  2. Cause One on Purpose
  3. What Git Tells You
  4. Reading the Conflict Markers
  5. Resolving It
  6. Resolving in VS Code
  7. Changed Your Mind? git merge --abort
  8. Keeping Conflicts Small
  9. Try It Yourself

1. What a Conflict Is (and Isn't)

In the last chapter, Git merged two branches by itself because they changed different parts of the project. A merge conflict happens when two branches change the same lines of the same file in different ways. Git has no way to know which version is right — maybe you want one, maybe the other, maybe a mix of both — so it stops and asks you.

A conflict is not:

  • an error or a sign you did something wrong
  • a broken repository
  • lost work — both versions are kept, side by side, until you choose

Conflicts are a normal part of working with other people, and they happen to experienced developers every week. Once you've resolved a few, they stop being scary.

2. Cause One on Purpose

The best way to learn is to make one. In my-site, make sure you're on main with a clean working tree:

git switch main
git status

Create a branch that changes the page title:

git switch -c new-title

In index.html, change the <title> line to:

    <title>Dara Sok — Personal Site</title>
git commit -am "Use full name in page title"

(-am stages every already-tracked file that changed and commits in one step. It doesn't include brand new files — those still need git add.)

Now go back to main and change the same line differently:

git switch main
    <title>Dara's Portfolio</title>
git commit -am "Rename site to portfolio"

Both branches have changed line 4 of index.html. Now merge:

git merge new-title

3. What Git Tells You

Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git merged everything it could and stopped at the conflict. You're now in the middle of a merge. Check where you are:

git status
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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

both modified names the file that needs your decision. In a bigger merge, files that merged cleanly would be listed separately under "Changes to be committed" — only the conflicted ones need you.

4. Reading the Conflict Markers

Open index.html. Git has written both versions into the file, surrounded by conflict markers:

  <head>
<<<<<<< HEAD
    <title>Dara's Portfolio</title>
=======
    <title>Dara Sok — Personal Site</title>
>>>>>>> new-title
  </head>

Read it as three parts:

MarkerMeaning
<<<<<<< HEADStart of your current branch's version (main, where you are)
=======The divider between the two versions
>>>>>>> new-titleEnd of the incoming branch's version (the one you're merging in)

Everything outside the markers merged fine. Only this block needs a decision.

5. Resolving It

To resolve a conflict, edit the file so it looks exactly how you want it, and delete all three marker lines. You have three choices:

  • keep yours: Dara's Portfolio
  • keep theirs: Dara Sok — Personal Site
  • write a mix: something new using both

Let's combine them. Replace the whole block, markers included, with:

  <head>
    <title>Dara Sok — Portfolio</title>
  </head>

Save the file, and double-check that no <<<<<<<, =======, or >>>>>>> lines are left anywhere in it. Then tell Git the conflict is resolved by staging the file, and finish the merge with a commit:

git add index.html
git commit

Your editor opens with the message Merge branch 'new-title' already written. Save and close.

git log --oneline --graph -5
*   a7f2c19 (HEAD -> main) Merge branch 'new-title'
|\
| * 4d81e0b (new-title) Use full name in page title
* | 9c3b5a6 Rename site to portfolio
|/
* 5a8c3e1 Merge branch 'add-contact'

Done. You've resolved your first merge conflict. Delete the branch with git branch -d new-title.

Resolving isn't just about the markers. Git only checks the lines that clashed. After a real conflict, open the page (or run the app and its tests) to make sure the combined result actually works.

6. Resolving in VS Code

VS Code recognises conflict markers and makes the choice easier. When you open a conflicted file, each conflict is highlighted, with small buttons above it:

  • Accept Current Change — keep your branch's version
  • Accept Incoming Change — keep the other branch's version
  • Accept Both Changes — keep both, one after the other
  • Compare Changes — see them side by side

Clicking one removes the markers for you. You can still edit the result afterwards. VS Code's Source Control panel (the branch icon in the left sidebar) also lists conflicted files under Merge Changes.

You still finish the same way: save, git add, git commit.

7. Changed Your Mind? git merge --abort

If you're halfway through resolving and want to start over — or you realise you merged the wrong branch — cancel the whole merge:

git merge --abort

Your project goes back to exactly how it was before you ran git merge. Nothing is lost, and you can try again whenever you're ready.

8. Keeping Conflicts Small

You can't avoid conflicts completely, but you can keep them rare and easy:

  • Keep branches short-lived. A branch that lives for two days conflicts much less than one that lives for two months.
  • Merge main into your branch often while you work, so you deal with small conflicts as they come instead of one giant one at the end.
  • Make small, focused commits. It's easier to decide between two small changes than two huge ones.
  • Talk to your team. If two people are about to rewrite the same file, a two-minute chat saves a painful merge.
  • Don't reformat whole files in the same branch as a real change. Changing every line's indentation conflicts with everyone.

9. Try It Yourself

  1. Cause and resolve the conflict above, combining both titles.
  2. Resolve one by choosing a side. Create two branches that change your <h1> differently, merge them into main one after the other, and resolve the conflict with VS Code's Accept Incoming Change.
  3. Abort a merge. Cause another conflict, look at the markers, then run git merge --abort. Run git status and git log --oneline to check that nothing changed.
  4. Conflict in two places. Make two branches that each change both the <title> and the <h1>. When you merge, you'll get two conflict blocks in the same file. Resolve both before committing.

You can now do everything Git offers on one computer. Next, let's put my-site on GitHub.

Buy Me a Coffee

Found this tutorial helpful? Consider buying me a coffee to support more free content!