What a conflict actually is
Git merges by region. If one branch changed the top of a file and the other changed the bottom, both changes go in and nobody is asked. Git stops only when both sides changed the same lines differently, because there is no rule that can decide which version you meant.
That is the whole of it. A conflict is not damage. It is git declining to guess.
Reading the markers
The file is left on disk with both versions inside it:
<<<<<<< HEAD
const fee = total * 0.05;
=======
const fee = Math.round(total * 0.05 * 100) / 100;
>>>>>>> paymentsAbove the ======= is the version on the branch you are on. Below it is the version from the branch you are merging in. The labels tell you which is which. Everything outside the markers has already been merged and needs no attention.
Resolving one
Open the file, decide (keep the top, keep the bottom, keep both, or write a third thing that combines them) and delete the three marker lines. Then:
git add src/checkout.ts
git commitEditors show buttons above each conflict: accept current, accept incoming, accept both. They do the same edit. git status lists every file still unresolved, so you can work through them one by one.
If you want out, git merge --abort returns the branch to exactly how it was before you started. Nothing is lost by trying a merge.
Conflicts that are not about your code
package-lock.json conflicts constantly, because two branches that each installed a package both rewrote it. Do not resolve it by hand. Take either side and regenerate:
git checkout --theirs package-lock.json # or --ours
npm install
git add package-lock.jsonGenerated files (build output, compiled CSS, snapshot files) get the same treatment. Regenerate rather than merge.
Migrations are the one generated-looking file that is not. Two branches that each added a migration numbered 0007 will merge cleanly, because they are different files, and then fail when the migration tool finds two sevens. Renumber one and check that it still applies after the other.
The agent and the conflict
Ask an agent to “fix the conflicts” and it will often resolve every one of them by taking one side wholesale. To a model reading the file, the markers are noise around code, and the quickest route to a file that parses is to keep one version. The other branch’s work vanishes without an error.
If you use an agent here at all, ask it to explain what each side of each conflict does before touching anything, and resolve the decision yourself. Conflicts are the moment when two intentions met, and only you hold both.
Avoiding most of them
Small branches, merged soon. Pull before you start. Do not reformat files you are not otherwise changing: formatting churn is the largest single source of conflicts, because it touches every line and collides with any real edit to the same file. Put the formatter in a pre-commit hook so everything is formatted the same way before it is ever committed, and this category nearly disappears.
The conflict nobody sees
A clean merge is not a correct merge. Two branches can each build perfectly and produce something that does not build together: one renamed a function, the other added a call to the old name in a different part of the file. The lines never overlapped, git had nothing to say, and the failure appears only when you run it.
Git tracks text. It knows nothing about functions, imports or types. So the merge is not finished when the commit exists; it is finished when npm run build passes and the two-minute check from the reading block has been done on the merged result. Treat every merge as a change, because it is one.
Every lesson here is open. Your progress is recorded once you pass the Building with AI exam.
Check your understanding
A merge completes with no conflicts reported. The app then fails to build with ‘cancelBooking is not defined’. What most likely happened?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Beatriz, your AI tutor
