Merge Conflicts
Listen to Episode 7: Merge Conflicts Are Not Scary - a conversational audio overview of this chapter. Listen before reading to preview the concepts, or after to reinforce what you learned.
Understanding, Preventing, and Resolving Conflicts
Merge conflicts sound intimidating but are a normal, manageable part of collaborative development. This guide explains what conflicts are, how to read conflict markers, and how to resolve them - step by step.
Workshop Recommendation (Chapter 7)
Chapter 7 uses one controlled practice challenge so students can learn conflict resolution without high-pressure scenarios.
- Challenge count: 1
- Time: under 10 minutes
- Evidence: issue-linked PR and completion comment
- Pattern: observe, resolve, verify
Chapter 7 Challenge Set
- Resolve conflict markers - identify and clean up conflict markers in a practice file, then open a linked PR.
Branch guidance for Chapter 7: Use a short-lived feature branch:
fix/yourname-issueXX(for example,fix/maria-issue48). The same pattern you used in Chapter 6.
Challenge 7.1 Step-by-Step: Resolve Conflict Markers
Goal: Identify the three types of conflict markers in a practice file, decide which content to keep, remove the markers, and submit a clean PR.
Where you are working: the learning-room repository on GitHub.com (web editor) or in VS Code if you cloned locally.
Before you start: Open your assigned Chapter 7 challenge issue (the one titled "Chapter 7.1: Resolve Conflict Markers (@yourname)"). The issue description tells you which practice file contains the conflict markers.
Practice sample: learning-room/docs/samples/chapter-6-conflict-practice-sample.md
- Open the practice file specified in your challenge issue.
- Search the file for
<<<<<<<. This is the start marker - it shows where the conflict begins. - Read the content between
<<<<<<<and=======. This is your version (the current branch). - Read the content between
=======and>>>>>>>. This is their version (the incoming branch). - Decide which content to keep:
- Keep only your version, or
- Keep only their version, or
- Combine both versions into one clean paragraph.
- Delete all three marker lines:
- The
<<<<<<< HEADline (or similar) - The
=======separator line - The
>>>>>>> branch-nameline
- The
- Review the file to confirm no marker lines remain. Search for
<<<<<<<again - there should be zero results. - Commit your changes on a branch named
fix/yourname-issueXX. - Open a pull request with:
- Title:
fix: resolve conflict markers in [filename] - Body: Include
Closes #XX(your challenge issue number) and a 1-2 sentence description of which content you kept and why.
- Title:
Screen reader tip: Use your screen reader's find command (Ctrl+F in browser, Ctrl+H in VS Code) to jump directly to <<<<<<<. The markers are plain text, so they are fully readable.
You are done when: Your PR passes bot validation checks and contains no remaining conflict markers.
Completing Chapter 7: Submit Your Evidence
When your PR is open and passing checks, post a comment on your assigned Chapter 7 challenge issue:
Chapter 7 completed:
- Challenge 7.1: Opened PR #[number] resolving conflict markers in [filename]
- Content decision: kept [your version / their version / combined both] because [reason]
Expected Outcomes
- Student can identify the three conflict marker lines (
<<<<<<<,=======,>>>>>>>) immediately. - Student can read both sides of a conflict and make an intentional content decision.
- Student can remove all markers and submit a clean, issue-linked PR.
If You Get Stuck
- Can't find the markers? Use
Ctrl+Fand search for<<<<<<<- they are always in sets of three. - Not sure which side to keep? Read both versions aloud. Pick the one that is clearer, or combine them.
- Accidentally deleted too much? Undo with
Ctrl+Zand start the section over. - PR bot says content is wrong? Double-check that zero marker lines remain - search for
<<<<<<<,=======, and>>>>>>>. - Ask facilitator to sanity-check your final content before opening the PR.
Learning Moment
Merge conflicts are not failures. They are a normal collaboration checkpoint and a chance to make an intentional content decision. In real open source projects, conflicts happen whenever two people edit near the same lines. The skill is not avoiding them - it is resolving them calmly and clearly.
Learning Pattern Used in This Chapter
- Start with a controlled, safe conflict (practice file with known markers).
- Learn to read the conflict structure (your version vs. their version).
- Make a deliberate content decision (not just deleting randomly).
- Submit clean evidence through the PR workflow.
- Build confidence for real conflicts in future contributions.
About Learning Cards in This Chapter
This chapter provides learning cards: expandable blocks that offer perspective-specific guidance for different ways of working. Not every card appears at every step. Open the ones that match how you work.
The following table describes the five learning card types used in this chapter.
| Card | Who it helps | What it covers |
|---|---|---|
| Visual / mouse | Sighted users navigating with a mouse or trackpad | Click targets, visual cues, color-coded conflict regions |
| Low vision | Users with magnification, zoom, or high-contrast themes | Zoom-friendly navigation, high contrast marker visibility, enlargement tips |
| NVDA / JAWS (Windows) | Screen reader users on Windows | Keystroke sequences, Focus and Browse mode, verbosity tips |
| VoiceOver (macOS) | Screen reader users on macOS | VO key sequences, rotor navigation, interaction model |
| CLI (git / gh) | Terminal users on any platform | Git and GitHub CLI commands for conflict detection and resolution |
Local Git Alternative: Resolving Conflicts from Your Terminal
If you cloned the learning-room in Block 0 and prefer resolving conflicts locally
The GitHub web conflict editor works well and is the primary method taught in this chapter. If you cloned the Learning Room in Block 0 and prefer working in your terminal, here is how to resolve conflicts locally. This is the same workflow covered in depth in Chapter 11: Git and Source Control.
Step 1 - Sync main and merge into your branch:
cd ~/Documents/learning-room
git checkout main
git pull origin main
git checkout your-branch-name
git merge main
If there is a conflict, Git will report which files are affected and stop the merge.
Step 2 - Open the conflicted file:
code docs/welcome.md # or your preferred editor
Look for the conflict markers:
<<<<<<< HEAD
Your version of the content
=======
The incoming version from main
>>>>>>> main
Step 3 - Resolve by editing:
- Keep the version you want (or combine both)
- Delete all three marker lines (
<<<<<<<,=======,>>>>>>>) - Save the file
Step 4 - Mark resolved, commit, and push:
git add docs/welcome.md
git commit -m "Resolve merge conflict in welcome.md"
git push
Your PR on GitHub updates automatically with the resolved content. The same bot checks and human review process apply.
What Is a Merge Conflict?
A merge conflict occurs when two people have both changed the same part of the same file in different ways, and Git cannot automatically decide which version is correct.
Git can merge changes automatically when they touch different parts of a file. Conflicts only happen when two changes overlap - for example:
- Person A changed line 12 to say "Submit form"
- Person B changed line 12 to say "Send message"
- Git asks: which one do you want to keep?
Why Conflicts Happen
The most common causes:
| Cause | Example |
|---|---|
| Two people edited the same line | You both fixed the same typo differently |
| One person deleted a file but another edited it | You removed an old function; they fixed a bug in it |
| Two people restructured the same section | You reorganized a list; they added items to it |
| A long-running PR diverged from main | Your branch is weeks old and main has changed significantly |
How to Prevent Conflicts (Prevention is Easier Than Resolution)
Avoiding conflicts in the first place saves time and reduces stress. Here are the most effective strategies:
1. Keep your branches short-lived
Work in small, focused chunks. A branch that lives for 3 days has far fewer conflicts than one that lives for 3 weeks.
- Target: 1-3 days from branch to merge
- If a feature takes longer, break it into smaller PRs
2. Sync with main frequently
The longer your branch diverges from main, the more likely conflicts become.
Best practice: Sync daily if main is active:
# From your feature branch
git fetch origin
git merge origin/main
# Or: git rebase origin/main (if comfortable with rebasing)
GitHub web method: Use the "Update branch" button on your PR if it appears.
3. Communicate with your team
Let others know what files you're working on. Use issue comments:
"Heads up: I'm working on the
[TODO]sections indocs/welcome.mdfor Challenge 3. If you're also editing welcome.md, let's coordinate so we don't conflict."
In the Learning Room, this is especially important because multiple students may claim challenges that touch the same file. Challenges 1 and 3 both modify docs/welcome.md - if two students work on both simultaneously without coordinating, a merge conflict will occur.
4. Avoid mass reformatting
Running a formatter on an entire file creates conflicts with anyone else editing that file. If you must:
- Do it in a separate PR before functional changes
- Announce it to the team
- Merge it quickly so everyone can sync
5. Pull before you push
Always fetch and merge (or pull) before pushing your changes:
git pull origin main # Sync your local main
git checkout your-branch
git merge main # Merge main into your branch
git push # Now push
This catches conflicts locally where they're easier to resolve.
6. Work on separate files when possible
If multiple people are working simultaneously, divide tasks by files or modules rather than everyone touching the same code.
7. Keep PRs small
A 50-file PR will almost certainly conflict with something. A 5-file PR merges quickly and cleanly.
The most effective contributors make many small PRs rather than one giant one.
8. Use Draft PRs for early visibility
Open your PR as a draft while still working. Others can see what you're changing and avoid overlapping work. Convert to "Ready for review" when done.
Advanced Prevention: Understanding Fast-Forward Merges
When your branch is perfectly up to date with main and adds new commits on top, GitHub can do a "fast-forward" merge - main simply moves forward to your latest commit. No merge commit needed. No possibility of conflicts.
How to achieve this: Rebase your branch on main right before merging:
git checkout your-branch
git fetch origin
git rebase origin/main
git push --force-with-lease # See warning below about force pushing
Warning: Force pushing rewrites history. Only do this on branches you alone control (not shared branches). Never force push to main.
For more on force pushing and rebasing, see the Glossary.
When Conflicts Are Actually Good
Conflicts indicate that multiple people are actively improving the project. In a healthy, collaborative environment, occasional conflicts are normal and manageable.
If you never have conflicts, it might mean:
- You're the only contributor (less review, less learning)
- PRs are moving too slowly (stagnation)
- People are avoiding working on important files (technical debt)
The goal isn't zero conflicts. The goal is catching them early, resolving them cleanly, and learning patterns that reduce future conflicts.
Spotting a Conflict on GitHub
When a PR has a merge conflict, you will see this message on the Conversation tab, near the merge section:
“This branch has conflicts that must be resolved”
You will also see a “Resolve conflicts” button. If you cannot see it (it may require write access), contact the PR author.
Visual / mouse users
Scroll to the bottom of the Conversation tab. The conflict message appears as a yellow or orange banner above the merge button area. Click Resolve conflicts to open the web conflict editor.
Low vision users (zoom, high contrast)
The conflict banner sits near the bottom of the Conversation tab, above the merge button area. If your browser zoom is at 200% or higher, you may need to scroll past lengthy comment threads to reach it.
- The banner uses a yellow or orange background. In Windows High Contrast mode, it renders with the system alert color so it remains visible.
- The Resolve conflicts button is a standard link-style button. If it is hard to target at high zoom, use
Tabto reach it after the merge status section and pressEnter. - If the button does not appear, you may lack write access to the repository. Ask the PR author or a maintainer for help.
Screen reader users (NVDA / JAWS - Windows)
- Press
Dto reach the bottom of the Conversation tab - Navigate down with
Hor↓past the comment threads - Find the heading or region containing "This branch has conflicts"
- Press
Bto find the Resolve conflicts button →Enter
Screen reader users (VoiceOver - macOS)
VO+U→ Landmarks orVO+Downto move toward the bottom of the Conversation tab- Quick Nav
HorVO+Cmd+Hpast comment headings until you reach the conflict notice - Quick Nav
Bto find the Resolve conflicts button →VO+Space
Conflict Markers - What They Mean
When conflict markers appear in a file, your editor is showing you both versions of the conflicted content so you can choose. The format is always:
<<<<<<< HEAD
The content that is on YOUR current branch
=======
The content coming from the OTHER branch (or main)
>>>>>>> branch-name-or-commit-hash
Breakdown
<<<<<<< HEAD- the start of YOUR version (HEAD = "the branch you are currently on")=======- the dividing line between the two versions>>>>>>> branch-name- the end of the INCOMING version (from the branch being merged in)
Example in a real file
Original file (docs/keyboard-shortcuts.md) before conflict
| Insert+Space | Toggle between Browse Mode and Focus Mode |
After two students both added a shortcut to the same table row
<<<<<<< HEAD
Insert+Space -- Toggle between Browse Mode and Focus Mode
Insert+F5 -- List elements by type
=======
Insert+Space -- Toggle between Browse Mode and Focus Mode
Insert+F7 -- Elements list (links, headings, form fields)
>>>>>>> add-nvda-shortcut
Resolution options
- Keep your version: add only
Insert+F5 - Keep their version: add only
Insert+F7 - Keep both rows: add both shortcuts to the table (often the right answer when two students added different valid shortcuts)
Resolving Conflicts on GitHub (Web Editor)
GitHub has a built-in conflict editor that you can use without any local tools.
Step-by-step: GitHub Conflict Editor
Visual / mouse users
- Click Resolve conflicts on the PR Conversation tab
- GitHub opens a full-page text editor showing each conflicted file
- The conflict markers are highlighted - everything between
<<<<<<and=======is your version; between=======and>>>>>>>is the incoming version - Edit the content directly: delete the lines you don’t want, including the three marker lines (
<<<,===,>>>) - When the file looks correct, click Mark as resolved (top-right of the file)
- If there are multiple conflicted files, a file list on the left lets you jump between them
- After all files are resolved, click Commit merge
Low vision users (zoom, high contrast)
- Open the conflict editor from the Resolve conflicts button on the PR Conversation tab.
- GitHub opens a monospace text editor. At 200% zoom or higher, the editor scrolls horizontally. Use
Shift+Scrollor horizontal scrollbar to navigate wide lines. - Conflict markers (
<<<<<<<,=======,>>>>>>>) are displayed in highlighted bands. In high-contrast themes, the markers use distinct system colors for good visibility. - The file list panel (left side) may collapse at high zoom levels. Look for a toggle or hamburger icon in the top-left corner to reopen it.
- Edit directly in the editor: delete unwanted lines, including all three marker lines.
- Click Mark as resolved in the top-right. At high zoom, this button may require horizontal scrolling to find. You can also
Tabto reach it. - After all files are resolved, click Commit merge.
Tip: Increase your browser's minimum font size (Settings, Appearance, Font size) for a more comfortable editing experience in the conflict editor. This setting persists across GitHub pages.
Screen reader users (NVDA / JAWS - Windows)
- Activate the Resolve conflicts button from the PR Conversation tab
- GitHub opens the conflict editor - a full-page text editor
- Navigate between conflicted files using the file list (press
NVDA+F7orVO+Uto find the file navigation panel) - Switch to Focus Mode (
NVDA+Space) to enter the text editor - Read the conflict markers line by line with
↓:<<<<<<< HEADmarks the start of your version=======is the dividing line>>>>>>> branch-namemarks the end of the incoming version
- Edit to keep the desired content - delete the conflict marker lines and the version you don't want
Tabto Mark as resolved button →Enter- Repeat for all conflicted files
Tabto Commit merge button →Enter
Screen reader users (VoiceOver - macOS)
- Activate the Resolve conflicts button from the PR Conversation tab
- GitHub opens the conflict editor - a full-page text editor
VO+U→ navigate to the file navigation panel to switch between conflicted filesVO+Shift+Downto interact with the text editorVO+Downto read the conflict markers line by line:<<<<<<< HEADmarks the start of your version=======is the dividing line>>>>>>> branch-namemarks the end of the incoming version
- Edit to keep the desired content - delete the conflict marker lines and the version you don't want
VO+Shift+Upto stop interacting, thenTabto Mark as resolved →VO+Space- Repeat for all conflicted files
Tabto Commit merge →VO+Space
What it looks like in the editor
When the conflict editor opens, your screen reader will announce a text editor. In Focus Mode, navigate with arrow keys. The content reads:
< < < < < < < H E A D
<button aria-label="Submit form">Submit</button>
= = = = = = =
<button type="submit">Send message</button>
> > > > > > > f e a t u r e / f o r m - i m p r o v e m e n t s
(Note: screen readers may spell out the < and > characters letter by letter - this is normal)
Resolving Conflicts in VS Code (Day 2)
VS Code has excellent merge conflict tooling with full screen reader support. This is covered in depth in Git & Source Control in VS Code, but here is an overview:
VS Code shows conflicts as
<<<<<<< HEAD (Current Change)
Your version
======= original -- (3-way merge, if enabled)
Original version before both edits
=======
Incoming version
>>>>>>> branch-name (Incoming Change)
VS Code merge conflict actions
Visual / mouse users
When your cursor is on a conflict region, VS Code shows CodeLens action links above the conflict block in the editor:
- Accept Current Change - keeps your version (HEAD)
- Accept Incoming Change - keeps the branch version being merged
- Accept Both Changes - keeps both (stacked one after the other)
- Compare Changes - opens a side-by-side diff
Click the link you want. The conflict markers disappear and your chosen content remains. Save the file with Ctrl+S.
Low vision users (zoom, high contrast)
VS Code highlights conflict regions with colored background bands:
- Current Change (your version) appears with a green-tinted background
- Incoming Change (their version) appears with a blue-tinted background
In high-contrast themes, these colors map to system theme colors that remain distinguishable. The CodeLens action links (Accept Current Change, Accept Incoming Change, Accept Both Changes, Compare Changes) appear as small text links above the conflict block.
Tips for comfort at high zoom:
- At 200% editor zoom (
Ctrl+=), the CodeLens links remain clickable. If they feel small, useCtrl+Shift+Pand typeMerge Conflict: Accept Current(orIncoming,Both) to trigger the same actions from the Command Palette without clicking. - Enable Editor, Minimap: Enabled = false in settings to reclaim horizontal space at high zoom.
- Use
Ctrl+Shift+Mto open the Problems panel. After resolving markers, this panel confirms no remaining conflict errors. - Use
F8(Next Problem) to jump between remaining conflict regions across the file without scrolling.
Screen reader users (NVDA / JAWS - Windows)
- Open the conflicted file
- Press
↓to navigate to a conflict marker (<<<<<<<) - The CodeLens links appear above - press
Tabto reach them - Press
Enteron your chosen action - Save the file (
Ctrl+S) - Stage the resolved file:
Ctrl+Shift+G→ find the file → Stage changes - Commit the merge
GitHub Copilot can help: With the cursor in a conflict region, open Copilot Chat (Ctrl+Shift+I) and type: "Resolve this merge conflict - keep meaningful changes from both sides." Copilot will suggest a resolution that you can review and accept.
Screen reader users (VoiceOver - macOS)
- Open the conflicted file
VO+Downor arrow keys to navigate to a conflict marker (<<<<<<<)- The CodeLens links appear above -
Tabto reach them VO+Spaceon your chosen action- Save the file (
Cmd+S) - Stage the resolved file:
Cmd+Shift+G→ find the file → Stage changes - Commit the merge
GitHub Copilot can help: With the cursor in a conflict region, open Copilot Chat (Cmd+Option+I) and type: "Resolve this merge conflict - keep meaningful changes from both sides." Copilot will suggest a resolution that you can review and accept.
When You Feel Stuck
Ask for help - it's normal
If you are unsure which version to keep:
- Leave a comment on the PR: "I have a merge conflict in
filename.jsand I'm not sure which version to keep - could someone help me understand the intent of these two changes?" - Tag the PR author or a maintainer with
@username
Abandon and start fresh (nuclear option)
If a conflict is severe (the branch diverged a lot from main):
- Close the PR without merging
- Start a new branch from the latest
main - Apply only your intended changes to the new branch
- Open a new PR
This is legitimate - not a failure.
Reading a Conflict Message from Git (Command Line Reference)
If you work locally, git merge or git pull will say:
CONFLICT (content): Merge conflict in src/index.html
Automatic merge failed; fix conflicts and then commit the result.
And git status will show:
both modified: src/index.html
These are normal outputs. The conflict markers are inserted into the file by Git - open the file and follow the steps above.
Git CLI alternative - resolving conflicts in the terminal
Resolve merge conflicts entirely from the command line:
# 1. Start the merge that causes the conflict
git merge main
# 2. See which files have conflicts
git status
# Look for "both modified:" entries
# 3. Open each conflicted file in your editor
# Edit the file: remove <<<<<<, =======, >>>>>> markers
# Keep the content you want
# 4. After editing, mark the file as resolved
git add src/index.html
# 5. Complete the merge
git commit
# Git auto-fills the merge commit message
# Check the result
git log --oneline -3
GitHub CLI (gh) alternative - checking PR conflict status
Check whether a PR has conflicts without opening a browser:
# View PR status (shows merge state)
gh pr view 42
# Check all PR checks and merge readiness
gh pr checks 42
# View the diff to understand what changed
gh pr diff 42
If conflicts exist, the gh pr view output shows "This branch has conflicts that must be resolved." Resolve locally using git merge (above) then push, or use the web editor.
Summary Checklist
Before you start:
□ My PR is small and focused (fewer conflicts = easier life)
□ I checked that others aren't editing the same files
When you see a conflict:
□ Don't panic - conflicts are normal
□ Read both versions (between <<< and ===, and between === and >>>)
□ Decide: keep one, keep both, or combine intelligently
□ Remove ALL three conflict marker lines (<<<, ===, >>>)
□ Verify the final file makes sense
□ Mark as resolved → Commit merge
After resolving:
□ Re-check that the PR description and issue link are still accurate
□ Comment on the PR: "Resolved merge conflict - kept both the aria-label and type attribute"
□ Request re-review if reviewers already approved before the conflict was introduced
Try It: Read a Conflict (Without Fear)
Time: 2 minutes | What you need: Any text editor or just read below
Read this merge conflict aloud. The goal is not to resolve it - just to understand what you're hearing:
The button should have an
<<<<<<< HEAD
aria-label="Submit form"
=======
aria-label="Send your response"
>>>>>>> feature-branch
attribute for screen readers.
Answer these three questions:
- What does your branch say? (The text between
<<<<<<< HEADand=======) - What does the other branch say? (The text between
=======and>>>>>>>) - Which version would you keep, and why?
You're done. You just read a merge conflict. That's the entire skill - everything else is just choosing which lines to keep and deleting the three marker lines.
What success feels like: Conflicts aren't mysterious anymore. They're just two versions side by side with markers telling you which is which. You already know how to pick the right one.
Day 2 Amplifier - Copilot Chat & Conflict Prevention
Resolve at least one conflict completely by hand before using any AI assistance. You must be able to read
<<<<<<<,=======, and>>>>>>>markers and understand what each version represents. An AI-suggested resolution you cannot independently verify is a liability - you are accepting a change you do not understand into a codebase other people depend on.Once you have mastered manual conflict resolution:
- In VS Code - Copilot Chat (
Ctrl+Shift+I) can explain a conflict in plain language - "Person A renamed the button to 'Submit Form'; Person B renamed it to 'Send Message'. Which intent should take priority?" - but you decide what survives- In your repo - Accessibility Agents'
@pr-reviewcan identify high-risk overlapping changes before a conflict occurs, flagging when two contributors are editing the same file area and giving you time to coordinate before it escalates- In the cloud - GitHub Agentic Workflows can detect stale PRs diverging from
mainand automatically notify contributors with a suggested rebase checklist - preventing the conflict before it is ever introducedUnderstanding conflict markers is not a stepping stone to letting AI handle conflicts. It is the skill that tells you when AI got it wrong.
Next: Culture and Etiquette Back: Working with Pull Requests Related: Git & Source Control in VS Code