Scenario
Section titled “Scenario”Two people edited the same lines of the same file on different branches. Merging one into the other, Git stops and reports a conflict.
A conflict is not an error. It is Git declining to guess which change is correct — because it cannot know.
Objective
Section titled “Objective”Create a genuine conflict, read the markers correctly, resolve it, and know how to abort when a resolution has gone wrong.
Prerequisites
Section titled “Prerequisites”- Git installed
- Comfortable with
git commitandgit switch - Git Merge provides the model this lab exercises
Starting state
Section titled “Starting state”mkdir -p /tmp/lab-conflict && cd /tmp/lab-conflictgit init -q .git config user.email "lab@example.com"git config user.name "Lab User"
cat > config.js <<'EOF'export const config = { timeout: 3000, retries: 3, endpoint: "https://api.example.com",};EOFgit add . && git commit -q -m "Add config"
# Branch A: the performance workgit switch -qc perf/timeoutssed -i 's/timeout: 3000/timeout: 500/' config.jsgit commit -qam "Reduce timeout for faster failure"
# Branch B: the reliability work, on the same linegit switch -q mainsed -i 's/timeout: 3000/timeout: 10000/' config.jsgit commit -qam "Raise timeout for slow networks"
git log --oneline --all --graphTwo branches. Both changed timeout. Both are defensible. Git will not choose.
-
Trigger the conflict:
Terminal window git merge perf/timeoutsExpected:
CONFLICT (content): Merge conflict in config.jsandAutomatic merge failed; fix conflicts and then commit the result. -
Inspect the state. Run
git status. Note thatconfig.jsis listed under “Unmerged paths” — it is neither staged nor unstaged, but in a third state. -
Read the file:
Terminal window cat config.jsIdentify which side is which.
HEADis the branch you are on —main, with the 10000 value. The other side is what you are merging in. -
Resolve it. Edit
config.jsso it contains exactly onetimeoutline and no conflict markers. For this lab choose 10000, the value that handles slow networks. -
Verify no markers remain:
Terminal window grep -nE '^(<<<<<<<|=======|>>>>>>>)' config.js && echo "MARKERS REMAIN" || echo "clean" -
Stage and commit:
Terminal window git add config.jsgit commit --no-edit -
Now practise aborting. Reset and redo the merge, then abandon it:
Terminal window git reset --hard HEAD~1git merge perf/timeoutsgit merge --abortgit statusConfirm you are back to a clean tree with no merge in progress.
Practice Mode (in your browser)
Educational Git simulator. Supports the commands needed for this exercise; it is not a complete Git installation. Nothing runs on your machine and nothing is sent anywhere — progress is kept in this browser only.
Objective: Merge `perf/timeouts` into `main`. Both branches changed `timeout` in `config.js`. Resolve the conflict keeping 10000 (the value that handles slow networks), then complete the merge. Estimated 8 minutes. Hints, a worked solution and a restart are available; success is checked against the repository state, so any correct route counts.
Open Practice Mode
Loading the simulator…
Keep building your Git skills. Get one practical technique, one workflow, and one security lesson each week. Modern Git Weekly is not taking subscriptions yet — read thesample issue, or follow new lessons by RSS.
What do the markers mean?
<<<<<<< HEAD timeout: 10000, ← your current branch======= timeout: 500, ← the branch being merged in>>>>>>> perf/timeoutsResolution means producing the correct final content. It does not have to be either side — it can be both, neither, or something new. Git only requires that the markers are gone.
git diff during a conflict shows a combined diff against both parents, which reads oddly
the first time. git diff --ours and git diff --theirs are usually clearer.
Taking one side wholesale:
git checkout --ours config.js # keep current branch's versiongit checkout --theirs config.js # take the incoming versionSolution
Section titled “Solution”git merge perf/timeouts# CONFLICT (content): Merge conflict in config.js
cat > config.js <<'EOF'export const config = { timeout: 10000, retries: 3, endpoint: "https://api.example.com",};EOF
grep -c '<<<<<<<' config.js # 0git add config.jsgit commit --no-editgit log --oneline --graphAborting instead:
git merge --abortExplanation
Section titled “Explanation”Git merges by three-way comparison. It looks at the merge base (the last common commit) and both tips. Where only one side changed a region, that change is taken automatically. Where both sides changed the same region differently, there is no correct automatic answer — so Git writes both versions into the file and stops.
Conflict markers are a working state, not corruption. The file is deliberately invalid so that committing it accidentally is hard.
The index tracks the conflict. During a conflict the index holds up to three versions of the
file — base, ours, theirs. git add collapses them to your resolution, which is why staging is
what marks a conflict resolved.
git merge --abort is always available while unresolved. It restores the pre-merge state
exactly. After the merge is committed you need git revert -m 1 <merge-sha> instead.
Clean up
Section titled “Clean up”cd /tmp && rm -rf lab-conflictRelated lessons
Section titled “Related lessons”Next lab
Section titled “Next lab”Repair a broken interactive rebase — the same conflict skills, under the harder conditions rebase creates.
How did this go?
Unexpected output. Compare your output with the expected block line by line; the first differing line is usually the cause. Then check the version-sensitive notes.
Missing prerequisite. Most "stuck" moments here come from one earlier concept. The prerequisites list names it; the learning path puts it in order.
Unclear explanation. Read the explanation section, then the mental model, then retry the step — the command usually makes sense once the model is in place.
Instructions did not match my environment. Check `git --version` and your shell (Git Bash vs PowerShell vs zsh). Platform notes on the page name the differences that matter; the verification step confirms you are back to a known state.
Good. The next step is to do it without the page open — or move to the recommended next activity below.
All help on this page: Git troubleshooting decision tree · Prerequisites for this page · The explanation section · Recover a lost commit (lab)