Learning Objectives
By the end of this lesson you will be able to:
- State the exact condition that causes a merge conflict
- Predict which changes will conflict and which will not
- Recognise the situations that produce conflicts most often in practice
- Reduce how frequently your team hits them
The Exact Condition
A conflict occurs when, since the merge base:
both branches changed the same lines of the same file, in different ways.
Every word in that sentence carries weight. Same file is not enough. Same file and overlapping lines and differing content is the condition.
There is a small set of related cases Git also cannot decide alone:
- One branch modified a file the other branch deleted
- Both branches added a new file at the same path, with different content
- One branch renamed a file the other branch modified heavily
They all reduce to the same principle: two answers, no rule for choosing.
What Does Not Conflict
This is the part worth internalising, because it dissolves most of the fear:
| Situation | Result |
|---|---|
| Different files changed | Clean merge |
| Same file, different functions or sections | Clean merge |
| Same file, one branch added at the top, other at the bottom | Clean merge |
| Both branches made the identical change | Clean merge |
| Same lines, different content | Conflict |
Git merges by content, not by file. Two people can work in one 2,000-line file all week and never conflict, as long as they stay in different neighbourhoods.
A Concrete Example
The merge base has this in config/test-env.yaml:
timeout: 30
retries: 2
base_url: https://staging.example.com
On main, someone raised the timeout:
timeout: 60
retries: 2
base_url: https://staging.example.com
On dev, someone else raised it differently and also changed retries:
timeout: 45
retries: 5
base_url: https://staging.example.com
Merging dev into main produces:
timeout— both branches changed the same line to different values → conflict. Git has no basis for preferring 60 over 45.retries— onlydevchanged it → clean. Git takes 5.base_url— neither changed it → clean. It stays as it was.
One conflicted line out of three. That is the typical shape of a real conflict: small, specific, and about a decision a human has to make.
Where Conflicts Actually Come From
In practice, a handful of patterns account for most of them:
Long-lived branches. A branch open for three weeks has three weeks of drift. This is the biggest single cause, and Lesson 2.3's refresh habit is the fix.
Shared configuration files. test-env.yaml, package.json, docker-compose.yml, CI pipeline definitions. Everyone touches them and they are small, so edits land close together.
Generated and lock files. package-lock.json, yarn.lock, compiled output committed to the repository. These regenerate completely on every change and conflict constantly. Most teams handle them by regenerating rather than merging.
Auto-formatters run at different times. One branch reformats a file, another edits it normally, and suddenly every line differs. This is why teams standardise on one formatter and one configuration.
Two people fixing the same bug. Rare, and mildly embarrassing, but it happens on busy teams and produces a genuinely tricky conflict.
Reducing Them
You cannot eliminate conflicts, and a team with zero conflicts is usually a team where nobody is working in parallel. But you can keep them small:
- Merge
maininto your branch often — daily ifmainis busy. - Keep branches short-lived. A branch that lives two days conflicts far less than one that lives two weeks.
- Commit in small, focused units. A conflict inside a 12-line commit is readable; one inside a 600-line commit is an ordeal.
- Say what you're touching. "I'm changing the timeout in test-env.yaml this afternoon" costs one message and prevents the whole thing.
Pro Tip: Before merging a branch that has been open a while, run
git diff main...your-branch --stat. If any file appears there that you know is also under active change onmain, you have just predicted your conflict — and you can deal with it deliberately instead of by surprise.
Key Takeaways
- A conflict needs the same lines of the same file changed differently on both sides
- Different files, different sections, or identical changes all merge cleanly
- Modify/delete, add/add and rename cases conflict for the same underlying reason
- Long-lived branches, shared configs, lock files and formatter runs cause most real conflicts
- Frequent refreshes and short-lived branches are the effective prevention
git diff main...branch --statpredicts where a conflict is likely before you merge