Corporate Software
How to resolve a git merge conflict: a step-by-step guide

Short answer
A git merge conflict happens when two branches change the same line in different ways. To fix it, run git status to find the conflicted files, choose the correct lines from between the <<<<<<</=======/>>>>>>> markers, delete the markers, mark the file with git add, and finish with git commit.
These steps work the same way on every editor and every operating system; the only thing that changes is which tool displays the merge conflict.
What is a merge conflict, and why does it happen?
When a team works on parallel branches of the same project, Git automatically merges most changes on its own. If two branches change the same line of the same file in different ways, or if one branch deletes a file that another branch has kept editing, Git cannot decide which change is correct. The merge stops, and a merge conflict appears. The whole point of a merge conflict is to stop an unsafe guess.
This is not a bug; it is a deliberate safety mechanism. According to Git’s official book, Git is smart about detecting when a merge result is unambiguous. When there is genuine ambiguity, it does not try to be clever about guessing. It leaves the decision to a person. Every merge conflict is Git saying that it would rather ask you than guess wrong.
Most conflicts stem from predictable day-to-day workflow overlaps. Two developers often edit the same function or the same configuration file simultaneously, leading to competing edits on the exact same lines. A feature branch that stayed apart from the main branch for a long time will inevitably collide after main has changed substantially. You also see conflicts when a file is deleted on one branch while another branch keeps editing it, or when automatic formatting tools reformat the same file differently across separate branches.
Finding conflicted files with git status
When a git merge or git pull command results in a merge conflict, you will see a message like this in the terminal:
Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
Automatic merge failed; fix conflicts and then commit the result.
Rather than tracking every merge-conflicted file through scattered terminal messages, running git status gives a reliable, complete list:
$ git status
On branch feature/checkout-form
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/app.js
both modified: src/config.json
The both modified label means that file has a merge conflict and both sides changed it. A large merge can produce a merge conflict in dozens of files at once, so seeing the full git status list before you start fixing anything is the first step to not missing one.
Reading the conflict markers
Git inserts its own markers directly into every file with a merge conflict. For example, if two branches changed the same line differently, the file looks like this:
<<<<<<< HEAD
Const VAT_RATE = 0.20;
=======
Const VAT_RATE = 0.18;
>>>>>>> feature/tax-update
You can read this block in three parts to understand what happened. The section between <<<<<<< HEAD and ======= is the version on the branch you currently have checked out, which is usually your own latest change. The section between ======= and >>>>>>> branch-name is the version from the branch you are merging in. The name after >>>>>>> tells you which branch the incoming change came from, which is useful for knowing who to talk to before deciding what stays.
The fix is to remove all three markers entirely and leave only the correct lines. Sometimes the right answer is to keep both sides, sometimes to combine them, and sometimes to discard both and write a third value. Git does not suggest an answer; the person reading the content decides.
How to resolve a git merge conflict, step by step
Resolving a merge conflict follows the same sequence regardless of which tool you use. You find the file, read the markers, decide on the correct content, clean up the markers, and commit the result.
Resolving it from the command line
Run git status first to list every conflicted file across your working tree. Open each conflicted file in a text editor and go through the conflict blocks one by one, deciding which lines should stay and removing the marker tags cleanly.
Mark each file as resolved with git add once the edits are complete:
Git add src/app.js
Git add src/config.json
Once every conflicted file has been staged with git add, finish the merge:
Git commit
Git usually proposes an automatic message for this commit, such as “Merge branch ‘feature/tax-update’”, which is fine to keep as-is in most cases. If the merge conflict turns out to be more complex than expected, or you realise you merged the wrong branch, git merge --abort cancels the merge and returns the branch to its clean state. This command works only before the merge commit has been finalized.
Resolving it in VS Code or another editor
A visual merge conflict tool makes resolving the merge conflict easier to follow. Editors like VS Code show clickable shortcuts such as “Accept Current Change”, “Accept Incoming Change”, and “Accept Both Changes” when you open a conflicted file. These shortcuts remove the markers behind the scenes and leave the correct lines in place. Visual tools lower the risk of syntax mistakes across multiple blocks, while the command line remains faster for small, single-line adjustments. Staging files with git add before confirming that every marker is gone remains a common mistake that lets stray symbols slip into production.
Merge conflicts in lock files and binary files
Auto-generated lock files such as package-lock.json, yarn.lock, or composer.lock produce conflicts frequently when dependencies update in parallel. Instead of resolving them line by line, deleting the lock file and re-running the package manager’s install command is usually safer because the dependency tree recalculates cleanly. Binary files like images, videos, and compiled packages cannot accept line-by-line markers. You must decide which whole version to keep, select it with git checkout --ours <file> or git checkout --theirs <file>, and stage the result with git add.
Resolving a merge conflict inside a GitHub pull request
When a pull request shows “This branch has conflicts that must be resolved”, GitHub offers two distinct paths forward. If the conflict is confined to a single non-binary file and is relatively simple, GitHub’s web-based conflict editor can handle it directly. It displays the standard markers inside the browser and turns your manual edit into a merge commit. GitHub’s official documentation walks through both web and command-line methods in detail.
When a merge conflict spans multiple files, involves a large binary file, or introduces structural code changes, resolving it in the browser becomes risky. Pulling the branch locally, resolving the conflict on your machine, testing the build, and pushing the resolved state is far safer. Resolving a merge conflict purely by choosing sides without running the code removes the conflict, but it does not guarantee a working result. Complex conflicts should always be followed by a local test run.
How rebase conflicts differ from merge conflicts
The same conflict markers and resolution logic apply when using git rebase, but the process unfolds differently. A standard merge resolves everything in a single moment and ends in one merge commit. A rebase reapplies every commit on your branch one at a time against the target branch. If the same line changed across multiple commits, the exact same conflict can appear repeatedly, pausing the rebase for each affected commit. After resolving each file, git add marks it and git rebase --continue moves on to the next commit. Running git rebase --abort cancels the sequence and returns the branch to its state before the rebase started.
Rebasing a shared branch that other developers are using carries extra risk because it rewrites public commit history. Deciding when that risk is acceptable belongs in the team’s version control and release agreements. The small-and-frequent-delivery principle from our DevOps guide applies directly to this workflow. The longer a branch stays apart from main, the more merge conflicts pile up and the more complex they get at merge time.
Ways to prevent merge conflicts
Eliminating every merge conflict entirely is not realistic in active software teams, but reducing their frequency and severity is straightforward. Keeping feature branches short-lived ensures that fewer changes accumulate before code returns to the trunk. Pulling from main regularly brings upstream updates into your branch early, letting you resolve small, isolated differences instead of facing an overwhelming diff later.
Architecture and team habits play an equal role in avoiding collisions. Keeping files small and focused lowers the chance that multiple developers edit the same logic simultaneously. Active communication about who is modifying specific shared modules helps teammates coordinate before conflicts arise. Teams should also lock formatting rules into a single shared configuration so that automated style adjustments do not create artificial conflicts on lines where business logic never changed.
Common mistakes
- Running git add without checking for stray markers. If marker tags remain in the file, they slip silently into the codebase and can take days or broken builds to catch.
- Picking one side out of panic. Choosing your change or the incoming change without reading both removes the conflict on paper, but it silently deletes necessary work written by your teammate.
- Skipping test suites after resolving. Text that looks clean to the human eye can still introduce runtime errors or broken imports that only automated tests or local execution reveal.
- Forgetting that aborting is an option. The
git merge --abortcommand restores your branch cleanly, but developers often panic and try manual undo operations after they should have simply aborted and regrouped. - Tolerating long-lived branches. When painful merges become routine, the solution is not faster manual conflict resolution, but changing branch lifespans so changes merge before diverge too far.
Checklist
Before committing a resolved conflict, run through these verification steps in order:
- Did you run
git statusto verify the complete list of conflicted files? - Did you inspect every conflict block across each file individually?
- Did you evaluate which change is objectively correct rather than defaulting to your own branch?
- Did you search the files to confirm no marker text was left behind?
- Did you execute your test suite or run the application locally after staging your changes?
- Does your commit message clearly state what was integrated and why?
Next step
A git merge conflict is unavoidable once a team grows and branches multiply, but it is always solvable when you work through it in the right order. What usually makes a merge conflict worse is not the conflict itself, but a rushed decision made under pressure. Finding the file with git status, reading the markers line by line, and never committing before testing the result resolves most cases safely.
If you want to set up your team’s version control workflow, branching strategy, or release process from the ground up, take a look at our corporate software solutions or get in touch with us. Our group company Web Tasarım Ofisi also supports web projects with technical infrastructure and long-term maintenance, including version control practices. The command-line habits that make conflicts less frequent are covered in SSH and essential Linux commands, and the longer-term cost of skipping this discipline in what technical debt is.
Related reading
Frequently asked questions
What is a git merge conflict?
A merge conflict happens when two branches change the same line of the same file in different ways, or when one branch deletes a file that the other branch has edited. Git cannot decide on its own which change is correct, so it pauses the merge and asks you to resolve it.
What is the difference between a merge conflict and a rebase conflict?
During a merge, Git tries to combine two branches and you hit a single conflict moment if they clash. During a rebase, each commit is reapplied one by one, so if the same line changed across several commits, the same conflict can appear multiple times, once per commit.
How should I read the conflict markers (<<<<<<<, =======, >>>>>>>)?
The section between <<<<<<< HEAD and ======= is the version on the branch you currently have checked out. The section between ======= and >>>>>>> is the version from the branch being merged in. Decide which lines should stay, then remove all three markers from the file.
When should I use git merge --abort?
If a conflict becomes too complex or you realise you merged the wrong branch, git merge --abort cancels the merge and returns the branch to its clean state before the merge started. It only works before the merge commit has been made.
How do I resolve a merge conflict inside a GitHub pull request?
If the conflict is simple, text-based, and confined to a single file, GitHub's web-based conflict editor can handle it. If the conflict spans multiple files, involves a binary file, or is structurally complex, resolving it locally on the command line and pushing the result is safer.