# Merge conflicts on GitHub: why they happen and what to do

> What a merge conflict on GitHub is and why two branches can clash on the same line, what "This branch has conflicts that must be resolved" means, how to read conflict markers and resolve a simple conflict in the browser, and why choosing the right text is a product decision.

- Course: [Git and GitHub for Product People](https://productovi.com/courses/git-for-product.md)
- Module: Branches and merges
- Lesson 6/15, ~34 min
- Source: https://productovi.com/courses/git-for-product/merge-conflicts

## Another grey button

**Alex Tutor:** An ordinary day on CatChow's product team, until a message arrives from Emma.

**Sofia:** Emma just messaged me in a panic. Her pull request #132 says "This branch has conflicts that must be resolved", and the merge button is grey. She thinks she broke the site.

**Alex Tutor:** Nothing is broken. A conflict blocks one merge and nothing else: `main`, the live site and Emma's work are all exactly as they were. The pull request just waits for someone to make a decision.

**Alex Tutor:** Here's how the two delivery pull requests look right now. The message is worded the way GitHub words it as of 2026.

```text
Delivery pull requests in catchow/website
- [Open] Rewrite delivery page copy #132: This branch has conflicts that must be resolved. Conflicting file: pages/delivery.md
- [Merged] Raise free-delivery threshold to 1000 UAH #133: Merged yesterday as commit 6f2c8a1
```

**Sofia:** #133 is Daniel's threshold change from last lesson. One of its commits was called "Update delivery page text".

**Daniel:** That's the collision. I changed one sentence on that page: the free-delivery line. Emma rewrote the whole page, that sentence included. Git got two different versions of one line and refused to guess.

> **Exercise:** Pull request #132 shows "This branch has conflicts that must be resolved". This means the delivery page on the live site is broken right now.

## "This branch has conflicts that must be resolved": why Git stopped

**Alex Tutor:** Here's how Git merges. It finds the commit where the two lines of work split, their common starting point, and compares each side with it.

**Alex Tutor:** If only one side changed a spot, Git takes that change. If the sides changed different files, or different parts of the same file, Git combines them on its own. That's most merges.

```text
Commit graph, oldest first: content/delivery-copy and main today
1. commit e7c3b19 on main "Add summer promo banner"
2. branch content/delivery-copy starts from commit e7c3b19
3. commit f02a6d4 on main "Update FAQ answers"
4. commit e19c3b7 on content/delivery-copy "Rewrite delivery page copy" (highlighted)
5. commit 8be2f70 on main "Add cat treats bundle"
6. commit 6f2c8a1 on main "Raise free-delivery threshold to 1000 UAH (#133)" (highlighted)
```

*Both lines start from e7c3b19. Each highlighted commit changed line 12 of pages/delivery.md in its own way. The branch is now 1 ahead and 3 behind.*

**Alex Tutor:** A **merge conflict** appears only when both sides changed the same lines, or lines right next to each other, in different ways. There is no rule for that case: which version wins is a decision, and Git leaves decisions to people.

> **Line 12 of `pages/delivery.md`, three versions**
>
> ```text
> e7c3b19, the starting point:  Free delivery on orders from 800 UAH.
> main, after #133:             Free delivery on orders from 1000 UAH.
> content/delivery-copy:        Orders from 800 UAH ship free, right to your door.
> ```
> Both branches changed the same line after the starting point, so Git stops and asks a person.

**Sofia:** So Daniel changed the number and Emma changed the words. Neither of them did anything wrong.

**Daniel:** Right. Now compare it with my checkout story from March. My branch and the cookie bar touched different files, so Git merged them without a word, and the result was broken.

**Alex Tutor:** Keep both halves of that in mind. No conflict doesn't mean the result is right. A conflict doesn't mean anyone made a mistake.

![Git combines changes to different files or parts on its own; only the same lines changed differently become a conflict, a question a person decides.](https://productovi.com/courses/git-for-product/diagrams/m2-l3-when-git-stops.png)

![Two people each hold a different puzzle piece toward the same gap in a jigsaw and pause to look at each other.](https://productovi.com/courses/git-for-product/inline/merge-conflicts-illustration-2.webp)

*A conflict isn't an error; it means both sides changed the same lines.*

> **Exercise:** Since Emma's branch split from `main`, both sides have changed something. In which cases will GitHub report a conflict? Select all that apply.

**Alex Tutor:** Now the other half of Daniel's March lesson, as a quick check.

> **Exercise:** Two pull requests were merged into `main` one after another, and GitHub reported no conflict: one changed the checkout button, the other added a cookie bar on a different file. What can you conclude?

## Reading the conflict markers

**Alex Tutor:** Back to #132. Under the conflict message there's a `Resolve conflicts` button. It opens a simple editor right on GitHub, with the conflicting file already loaded.

**Sofia:** Emma is sharing her screen and clicking it now. It looks like a plain text file with strange arrows in the middle.

> **`pages/delivery.md` in GitHub's conflict editor**
>
> ```text
> ## Delivery
>
> <<<<<<< content/delivery-copy
> Orders from 800 UAH ship free, right to your door.
> =======
> Free delivery on orders from 1000 UAH.
> >>>>>>> main
>
> Couriers deliver within one day in Kyiv.
> ```
> The version from Emma's branch sits above the divider, the version from `main` below it. The heading and the courier line are outside the markers: nothing to decide there.

**Alex Tutor:** These are **conflict markers**. `<<<<<<<` opens the conflict and names the branch the upper version came from. `=======` divides the two versions. `>>>>>>>` closes the conflict and names the other branch.

**Alex Tutor:** Everything outside the markers is settled. Only the part between the arrows waits for a human. And the markers themselves aren't text for the page: they have to go.

**Daniel:** Engineers see exactly the same markers in their code editor after running `git merge` in the terminal. Same arrows, different window.

**Sofia:** Seven characters on each side. Somebody really wanted them impossible to miss.

> **Exercise:** Match each part of the conflict in `pages/delivery.md` with what it means.

## A question about intent

**Sofia:** Emma's first instinct: keep her version. It's her pull request, after all.

**Alex Tutor:** Then the page would promise free delivery from 800 UAH, while the cart makes it free only from 1000. Customers would pay for delivery the page called free.

**Sofia:** And keeping Daniel's line throws away Emma's rewrite. So the right answer is neither: Emma's words with Daniel's number.

**Alex Tutor:** That's the heart of this lesson. A conflict isn't an error, it's a question: what did each person mean, and what should the page say now? Git can't answer that. You can.

![Two colleagues at a table, one with a small orange price sticker and one with a freshly rewritten page, stick it onto the new page together.](https://productovi.com/courses/git-for-product/inline/merge-conflicts-illustration-3.webp)

**Daniel:** Honestly, this is where I need a PM. I can resolve any conflict technically. I can't know whether finance changed its mind again, or which wording marketing approved.

**Alex Tutor:** In the editor you can keep one side, keep both, or write something new. Here it's something new: one line built from both.

> **Exercise:** The conflict in `pages/delivery.md`:
>
> ```text
> <<<<<<< content/delivery-copy
> Orders from 800 UAH ship free, right to your door.
> =======
> Free delivery on orders from 1000 UAH.
> >>>>>>> main
> ```
>
> The threshold went up to 1000 UAH in #133 at finance's request, and marketing approved Emma's new wording. What should replace the whole block, markers included?

## How to resolve a merge conflict on GitHub

**Alex Tutor:** Resolving takes three steps in the editor: fix the text, press `Mark as resolved`, then `Commit merge`. First, Emma replaces the whole block with the agreed line: "Orders from 1000 UAH ship free, right to your door." The three marker lines go too.

**Daniel:** Check that twice. In the terminal nothing stops you from committing a leftover `=======`, and then it turns up on the live page. I've seen it happen. To other people, of course.

**Alex Tutor:** When the file is clean, `Mark as resolved` tells GitHub this file is settled. If several files conflict, you pick the next one from the list on the left and repeat.

**Sofia:** Here there's only one. So the last button is `Commit merge`.

**Alex Tutor:** Right. Once Emma presses it, check the result the way a reviewer would: the pull request's `Files changed` tab should now show just Emma's rewrite, with 1000 in line 12 and no trace of 800.

> **Exercise:** Put the steps for resolving the conflict in #132 on GitHub in order.

**Alex Tutor:** Daniel's warning about leftover markers is worth a check of its own.

> **Exercise:** If someone forgets to delete a `=======` line while resolving a conflict, Git removes it automatically when the merge is committed.

## Where the resolution lands

**Sofia:** What does `Commit merge` actually commit? And where?

**Alex Tutor:** A merge commit on Emma's branch, not on `main`. GitHub merges `main` into `content/delivery-copy`, with your decision inside. As of 2026 its message reads "Merge branch 'main' into content/delivery-copy".

```text
Commit graph, oldest first: After Commit merge
1. commit e7c3b19 on main "Add summer promo banner"
2. branch content/delivery-copy starts from commit e7c3b19
3. commit f02a6d4 on main "Update FAQ answers"
4. commit e19c3b7 on content/delivery-copy "Rewrite delivery page copy"
5. commit 8be2f70 on main "Add cat treats bundle"
6. commit 6f2c8a1 on main "Raise free-delivery threshold to 1000 UAH (#133)"
7. merge commit c90d4e7: main merged into content/delivery-copy "Merge branch 'main' into content/delivery-copy" (highlighted)
```

*The merge runs from main into the branch. content/delivery-copy now has everything from main plus Emma's rewrite; main itself hasn't changed.*

**Sofia:** So the branch is zero behind now, and the conflict message is gone.

**Daniel:** And the merge button is back, waiting for my review. Since we squash, that merge commit never reaches `main`'s history: `main` gets one clean commit for #132.

**Alex Tutor:** One more thing to read in that graph: which way the merge goes. Resolving a conflict on GitHub updates the pull request's branch. The site changes only when the pull request itself is merged.

> **Exercise:** Someone resolved a conflict in pull request #145 with GitHub's editor. What does the highlighted commit b2 tell you?

## Who resolves, and when the browser isn't enough

**Alex Tutor:** The web editor handles one kind of conflict: different edits to the same lines of a text file. That covers most conflicts in copy.

**Alex Tutor:** Other kinds need the command line: say one branch deleted a file the other edited, or both replaced the same image. As of 2026 GitHub then deactivates `Resolve conflicts` and says the conflict is too complex for the web editor.

**Daniel:** That's my job, not yours. But I'd still come to you with the same question: what should the result be?

**Alex Tutor:** So who resolves? Usually the author of the blocked pull request, together with the author of the change it collided with. The PM brings the answer to "what should it say?".

**Sofia:** So my part: find out what each side meant, agree on the result, write the decision in the pull request and check `Files changed` afterwards.

**Alex Tutor:** And what not to do: pick a side just to turn the button green, resolve conflicts in code or config you don't understand, or edit someone else's branch without asking.

> **Exercise:** A copy conflict blocks a pull request for a page you're responsible for. Which of these are part of a PM's job? Select all that apply.

## Fewer conflicts next time

**Alex Tutor:** Why did this one happen at all? Emma's branch lived for more than a week and rewrote a whole page. Meanwhile `main` moved on without it.

**Sofia:** Three commits behind by now. On the branches page last time it was two.

**Daniel:** Each of those commits was a chance to collide. The longer a branch lives and the more it touches, the more `main` changes underneath it.

**Alex Tutor:** That's why this module keeps repeating the same habits: small branches, one task each, merged within days. And bring fresh `main` into a longer branch early, while conflicts are still small.

**Alex Tutor:** And talk. One line in the team chat, "I'm rewriting the delivery page this week", and Daniel would have pinged Emma before touching that sentence.

![At neighbouring desks, one colleague leans over to say a quick word, pointing at the same page shown on both screens.](https://productovi.com/courses/git-for-product/inline/merge-conflicts-illustration-4.webp)

**Sofia:** Which is a PM job too: knowing that finance and marketing are changing the same page in the same week.

> **Exercise:** Which of these pull requests is most likely to run into a merge conflict?

## Leave the reason behind

**Alex Tutor:** Last task. Daniel reviews #132 tomorrow, and he'll see a line that matches neither his version nor Emma's original.

**Alex Tutor:** Write a comment for the pull request: what line 12 says now and why. Two or three sentences.

**Daniel:** Mention where the 1000 came from. In a year somebody will run blame on that line, follow it to #132 and land right on your comment.

**Sofia:** A note for the next detective. I know exactly how that feels.

> **Exercise:** Daniel will review pull request #132 tomorrow. Line 12 of `pages/delivery.md` now reads "Orders from 1000 UAH ship free, right to your door.", which matches neither his version nor Emma's original. Write a 2–3 sentence comment on #132: what the line says after the conflict was resolved, and why.

**Alex Tutor:** Daniel approved, Emma merged, and the delivery page now reads "Orders from 1000 UAH ship free, right to your door." That's module 2: branches, merges and the conflicts between them.

**Sofia:** And the checkout fix? #134 has been a draft for a while now.

**Daniel:** Almost ready for review. Next module is all about pull requests, and you'll get to read mine tab by tab.

- Previous lesson: [Merging on GitHub: merge commit, squash and merge, rebase](https://productovi.com/courses/git-for-product/merging.md)
- Next lesson: [What is a pull request? Anatomy of a PR page](https://productovi.com/courses/git-for-product/pull-request-anatomy.md)

---
Productovi Learning. Free, no sign-up needed to read.
