Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Resolve Git Merge Conflicts Confidently

By Kokil Thapa | Last reviewed: September 2026

You edited the same line as a teammate. Git stopped and asked you to resolve Git merge conflicts confidently before it could finish the merge. That pause feels scary on a Friday deploy. It is normal on any shared codebase — Laravel apps, WordPress themes, or a custom web project in Nepal. The fix is not memorising magic commands. You need a repeatable workflow: read the markers, choose the correct hunk, test, and commit. This guide walks through that process with copy-paste commands you can use today.

What causes Git merge conflicts during a merge or pull?

Git merges two histories by replaying commits from one branch onto another. Most of the time it auto-merges cleanly. A conflict appears when both branches changed the same lines — or one branch deleted what the other edited.

Common triggers include two developers renaming the same route, both updating a Composer lock file, or a long-lived feature branch drifting from main. On production systems I maintain with Git branching strategies, conflicts often cluster around config files, migrations, and compiled assets.

Why Git Merge Conflicts Happenmain branchLine 42 changedfeature branchLine 42 changedSame lines editedGit cannot auto-pickResult: CONFLICT statusManual resolution required
Git merge conflicts appear when two branches modify overlapping lines Git cannot reconcile automatically.

Binary files — images, compiled PDFs, vendor zips — also conflict. Git will not merge them inline. You must pick one entire version. Rename conflicts happen when two branches move the same file to different paths. Git labels these as both modified, both deleted, or added by both in git status.

Typical conflict hotspots in web projects

  • Lock files: composer.lock, package-lock.json, or yarn.lock after dependency bumps on parallel branches.
  • Database migrations: two Laravel migrations with the same timestamp prefix.
  • Environment templates: .env.example keys added on both sides.
  • Route and config files: duplicate entries in routes/web.php or config/app.php.
  • Build artefacts: committed CSS or JS bundles when teams disagree on build-in-CI policy.

Understanding the cause speeds resolution. A lock-file conflict usually means re-running Composer or npm after picking one side. A migration conflict may need renaming one file and re-running php artisan migrate.

How do you resolve Git merge conflicts step by step?

This is the workflow I use on every conflict — from solo side projects to multi-developer Laravel repos deployed with GitLab CI. Follow the steps in order. Do not skip the test step.

  1. Confirm state: run git status and note files listed under Unmerged paths.
  2. Choose strategy: manual edit, merge tool, or accept one side wholesale with --ours / --theirs.
  3. Edit each file: remove conflict markers and leave valid code.
  4. Stage resolved files: git add <file> for each one.
  5. Verify: run tests, lint, or at minimum boot the app locally.
  6. Complete the merge: git commit (Git pre-fills a merge message).

Start the merge and inspect status

git checkout main
git pull origin main
git merge feature/booking-refactor

git status

Output shows both modified next to conflicted paths. For a pull that failed mid-merge, Git leaves you in the same state. Finish the resolution locally before pushing.

Read conflict markers in the file

Git wraps each conflicting hunk with standard markers. Your job is to delete the markers and keep the correct code — sometimes both sides combined.

<<<<<<< HEAD
return redirect()->route('dashboard');
=======
return redirect()->route('bookings.index');
>>>>>>> feature/booking-refactor

HEAD is your current branch — often main during a merge. The section after ======= comes from the branch you are merging in. Neither block includes the markers in the final file.

Conflict Marker Anatomy<<<<<<< HEAD (current branch / ours)Your version of the codeKeep, discard, or merge with incoming======= separatorIncoming branch versionFrom feature branch being merged>>>>>>> branch-name
Every Git merge conflict hunk uses HEAD, separator, and incoming markers you must remove after choosing code.

Resolve, stage, and commit

After editing, the file must contain zero marker lines. Stage it explicitly — Git will not assume you finished because you saved the file.

git add app/Http/Controllers/BookingController.php
git status

git commit

The default merge commit message is fine unless your team requires a ticket reference. Push only after local verification passes.

git push origin main

On a booking platform like Adventure Third Pole Trek, I once merged parallel Livewire component changes. Both sides added different validation rules. The correct fix kept both rule sets — not either branch alone.

Which Git commands and merge tools speed up conflict resolution?

Manual editing works for small conflicts. Larger merges across dozens of files benefit from visual merge tools or targeted one-side commands. Pick the approach that matches conflict size and your comfort level.

MethodBest forCommand or toolRisk level
Manual edit in IDE1–5 files, logic conflictsVS Code, PhpStorm built-in UILow if you read both sides
Git mergetoolMany files, complex hunksgit mergetool + vimdiff, meld, kdiff3Low with review
Accept ours entirelyRegenerated lock file on maingit checkout --ours pathMedium — verify dependencies
Accept theirs entirelyFeature branch owns the filegit checkout --theirs pathMedium — may overwrite fixes
Abort mergeWrong branch or too messygit merge --abortSafe reset to pre-merge state

Configure and launch a merge tool

Git ships with mergetool support. Configure your preference once per machine.

git config --global merge.tool vimdiff
git mergetool

Each conflicted file opens sequentially. Saving in the tool stages the result. When finished, run git status to confirm no unmerged paths remain. Official reference: git-mergetool documentation.

Use ours and theirs with intent

During an active merge, --ours means the branch you checked out. --theirs means the branch being merged in. This trips people up during rebases — ours and theirs swap roles. When rebasing, read labels carefully or stick to manual edits.

git checkout --ours composer.lock
composer install
git add composer.lock

For a JSON config conflict, a quick sanity pass through a JSON formatter catches trailing commas you introduce while merging by hand.

Compare versions without resolving yet

git diff
git diff --name-only --diff-filter=U
git show :2:path/to/file.php
git show :3:path/to/file.php

Stages :2 and :3 represent ours and theirs in the index during a merge. Useful when you want context before opening the editor. If you need to undo a bad edit mid-resolution, git checkout -m -- path/to/file restores conflict markers.

Merge Conflict Resolution Workflowgit mergeConflict?Edit / mergetoolRemove markersgit addRun tests / lint / boot appphp artisan test, npm run buildgit commitgit pushStuck? git merge --abort returns to pre-merge state
Step-by-step workflow to resolve Git merge conflicts confidently from first conflict through tested commit.

How do you prevent merge conflicts on shared development teams?

Prevention beats heroics. Teams that merge small and often see fewer conflicts than teams with month-long feature branches. Trunk-based development with short-lived branches is the pattern I prefer on client projects where deploy cadence matters.

Branch hygiene that actually works

  • Pull before you push: sync main into your feature branch daily, not only at PR time.
  • Keep PRs small: under 400 lines changed when possible — easier review and fewer overlap collisions.
  • Own file boundaries: split tasks so two developers rarely touch the same controller in one sprint.
  • Regenerate, do not hand-merge: for lock files, accept one side then run composer update or npm install.
  • Enforce CI gates: pipelines that run PHPUnit and ESLint catch broken merges before production.

Pair this with Git hooks that automate checks so conflict resolution never commits a syntax error. On sister sites sharing a Deployer pipeline, a bad merge caught locally saves a broken symlink deploy.

Rebase vs merge for feature integration

Both integrate changes. They create different history shapes and different conflict timing. Read the full comparison in Git rebase vs merge before standardising team policy.

Rebasing replays your commits atop updated main. You fix conflicts commit-by-commit. Merging pulls main into your branch once — one conflict session. Neither eliminates conflicts. They only schedule when you confront them.

For Laravel 13 projects on PHP 8.3+, I align team policy with what CI expects. If your pipeline validates linear history, document rebase rules clearly. Ambiguity causes force-push accidents.

Communication beats tooling alone

Announce when you rename shared classes or shuffle migrations. A two-line Slack message prevents a four-file conflict later. For legal-tech portals such as Court Marriage In Nepal, content and code changes often overlap in Blade templates — coordinate with whoever edits copy.

Prevent Merge Conflicts: Team HabitsDoShort-lived branchesDaily sync from mainSmall focused PRsAvoidMonth-long feature branchesMega-PRs touching 40 filesSilent parallel refactorsCI pipeline on every PRTests catch bad merges before deployResult: fewer conflicts, faster reviews
Team habits that reduce how often you must resolve Git merge conflicts confidently under deadline pressure.

When should you abort a merge and try a different approach?

Not every conflict session should end in a merge commit. Sometimes the safest move is to stop, reset, and replan. Knowing when to abort is part of resolving Git merge conflicts confidently — not a sign of failure.

Abort and return to a clean tree

git merge --abort

This works only during an in-progress merge. Your working tree returns to the pre-merge snapshot. Uncommitted local edits outside conflicted files may still need stashing first. Check with git status.

Scenarios where abort makes sense

  • You merged the wrong branch — easy fix, no need to untangle hunks.
  • Conflicts span hundreds of files because the feature branch is months stale.
  • You lack domain context to choose between two valid business logic paths.
  • Conflict markers accidentally committed on a prior bad resolution attempt.

In the stale-branch case, prefer rebasing or recreating the feature atop current main in a fresh branch. Copy unpushed commits with git cherry-pick. See Git cherry-pick explained for selective replay. If you already committed broken markers, git reflog helps — covered in recover lost commits with git reflog.

Pull with rebase as an alternative entry point

git pull --rebase origin main

This replays your local commits on top of remote main. Conflicts appear per commit rather than in one merge commit. Some developers find that easier to reason about. Official merge docs live at git-scm.com/docs/git-merge.

During a rebase conflict, use git rebase --continue after fixing each commit. Use git rebase --abort to bail out entirely. Never force-push a shared branch without team agreement.

Security check after messy merges

A rushed conflict resolution can reintroduce removed credentials or drop security middleware. After any large merge, scan for accidental secret commits. Our CI guide on secrets scanning in Git with Gitleaks shows how to automate that gate.

On production maintenance contracts through support and maintenance services, I treat post-merge review as non-optional. A two-minute diff scan beats a midnight outage.

Key Takeaways

  • Merge conflicts mean Git needs human judgment on overlapping edits — not a broken repository.
  • Read <<<<<<< HEAD hunks carefully, remove all markers, then git add each resolved file before committing.
  • Use git mergetool, --ours, or --theirs for bulk files like lock files — then regenerate dependencies.
  • Prevent conflicts with short branches, daily syncs from main, small PRs, and CI that runs tests on every merge.
  • Abort with git merge --abort when the branch is wrong or the merge scope is too large to trust.
  • Always test after resolving — conflict-free syntax does not guarantee correct application behaviour.

People Also Ask

What do the <<<<<<< HEAD markers mean in a merge conflict?

They delimit the version from your current branch — the one checked out when you ran merge or pull. Everything between <<<<<<< HEAD and ======= is yours. Delete the markers and keep, combine, or discard that block based on intent.

Can I resolve all merge conflicts in VS Code or PhpStorm?

Yes. Both IDEs detect conflict markers and offer inline buttons: Accept Current, Accept Incoming, Accept Both, or Compare. The underlying task is identical to manual editing — choose code, remove markers, stage, commit. IDE buttons just automate the deletion step.

Is it safe to delete one entire side of a conflict?

Safe only when you understand what that side changed. Blindly accepting incoming code can drop hotfixes sitting on main. Read the surrounding context and the original commits with git log -p when unsure.

What happens if I commit without removing conflict markers?

Git allows it if you manually staged the file after a sloppy edit. Your codebase now contains literal <<<<<<< lines. PHP will throw parse errors. CI should fail. Fix with a follow-up commit or an interactive rebase before pushing if the bad commit is still local.

Ship cleaner merges on your next project

You now have a full workflow to resolve Git merge conflicts confidently — from reading markers through testing and push. The skill compounds: small daily syncs, clear branch policy, and CI gates mean you face fewer conflicts over time. When they do appear, you treat them as ordinary integration work, not emergencies.

If your team fights the same conflict patterns on every sprint — stale branches, lock-file wars, migration clashes — structured process help pays for itself quickly. Review related guides on merge conflict tactics, AI code review in CI, and AI-assisted debugging workflows. For server-side Git workflows on Ubuntu, see Linux system administration.

Need hands-on help untangling a legacy repo or setting up safer deploy pipelines? Contact us to discuss your project. You can also browse the portfolio for examples of production apps shipped with disciplined Git workflows, or learn more about my background building and maintaining these systems since 2010.

Frequently Asked Questions

Git merge conflicts appear when two branches modify overlapping lines Git cannot reconcile automatically. Common triggers include two developers editing the same route, both updating composer.lock or package-lock.json, or a long-lived feature branch drifting from main. Conflicts also hit binary files, rename collisions, and hotspots like Laravel migrations, .env.example, routes/web.php, and committed build artefacts.

Run git merge or git pull, then git status to list unmerged paths. Edit each conflicted file: remove all >>>>>> markers while keeping valid code — sometimes combining both sides. Stage each file with git add, run tests or boot the app locally, finish with git commit, and push only after verification passes. Do not skip the test step.

They delimit your current branch's version — the branch checked out when you ran merge or pull. Everything between

Yes. Both IDEs detect conflict markers and offer inline actions: Accept Current, Accept Incoming, Accept Both, or Compare. The underlying work is identical to manual editing — choose the correct code, remove all markers, stage with git add, then commit. IDE buttons mainly automate marker deletion; you still need to verify the merged logic makes sense before pushing.

Safe only when you understand what that side changed. Blindly accepting incoming code can drop hotfixes sitting on main. Read surrounding context and review original commits with git log -p when unsure. For regenerated lock files, accepting one side then running composer install or npm install is often correct — but verify dependencies still resolve and the application boots before you commit the merge.

Git allows it if you manually staged the file after a sloppy edit. Your codebase now contains literal

Manual IDE editing suits one to five logic conflicts. git mergetool opens vimdiff, meld, or kdiff3 for many files. git checkout --ours or --theirs accepts one side wholesale — useful for lock files before regenerating dependencies. git diff --name-only --diff-filter=U lists unmerged paths. git show :2:path and git show :3:path compare ours and theirs. git checkout -m -- path restores markers after a bad edit.

During an active merge, --ours is the branch you checked out and --theirs is the branch being merged in. Example: git checkout --ours composer.lock followed by composer install and git add. During a rebase these labels swap — ours becomes the upstream branch and theirs becomes your replayed commits. When rebasing, read labels carefully or stick to manual edits to avoid picking the wrong version.

Use git merge --abort during an in-progress merge to return to the pre-merge snapshot. Abort when you merged the wrong branch, conflicts span hundreds of files because the feature branch is months stale, you lack domain context to choose between valid business logic paths, or conflict markers were accidentally committed earlier. For stale branches, rebase or recreate the feature atop current main and cherry-pick unpushed commits instead of untangling a massive merge.

Pull before you push and sync main into feature branches daily, not only at PR time. Keep PRs under 400 lines when possible. Split tasks so two developers rarely touch the same controller. Regenerate lock files instead of hand-merging — accept one side then run composer update or npm install. Enforce CI gates running PHPUnit and ESLint. Announce shared renames and migration shuffles. Short-lived branches beat month-long feature branches every time.

Lock files — composer.lock, package-lock.json, yarn.lock — after parallel dependency bumps. Database migrations when two Laravel migrations share the same timestamp prefix. Environment templates when .env.example keys are added on both sides. Route and config files with duplicate entries in routes/web.php or config/app.php. Build artefacts when teams disagree on committing compiled CSS or JS bundles. Understanding the file type speeds resolution.

Do not hand-merge JSON line by line. Accept one side with git checkout --ours composer.lock or git checkout --theirs composer.lock, then regenerate dependencies with composer install or npm install. Stage the updated lock file with git add. Run a quick sanity pass through a JSON formatter if you merged a config file manually — trailing commas break parsers. Verify the application boots and CI passes before pushing the merge commit.

Neither eliminates conflicts — they only schedule when you confront them. Merging pulls main into your branch once for a single conflict session. Rebasing replays your commits atop updated main, fixing conflicts commit by commit; git pull --rebase origin main is an alternative entry point. Align team policy with what CI expects. If your pipeline validates linear history, document rebase rules clearly — ambiguity causes force-push accidents on shared branches.

Git will not merge binary files — images, compiled PDFs, vendor zips — inline. You must pick one entire version using git checkout --ours or git checkout --theirs on the file path, then git add it. There are no conflict markers to edit. Confirm with teammates which branch owns the authoritative asset before choosing. After resolution, verify the file opens correctly and any references in code still point to the right path.

A rushed conflict resolution can reintroduce removed credentials or drop security middleware. After any large merge, scan the diff for accidental secret commits — automate this gate with Gitleaks in CI. Treat post-merge review as non-optional on production maintenance work: a two-minute diff scan beats a midnight outage. Run your normal test suite too, because conflict-free syntax does not guarantee correct application behaviour or intact security layers.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: