Komitly
BlogPricing
Home/Blog/Resolving Merge Conflicts: A Step-by-Step Guide
BranchingBeginner

Resolving Merge Conflicts: A Step-by-Step Guide

Komitly·February 27, 2026·10 min read
merge conflictgit mergeconflict resolution3-way mergeconflict markers
Loading article...

On this page

  • What is a merge conflict?
  • How conflicts happen
  • Reading conflict markers
  • Resolving conflicts step by step
  • Resolving conflicts in Komitly
  • Preventing conflicts
  • Summary

Try it visually with Komitly

Stop memorizing commands. See your branches, commits, and merges in a beautiful visual interface.

Download Komitly — Free

Related articles

BranchingBeginner

Git Branches Explained: Create, Switch, and Manage

Understand Git branches from the ground up. Learn to create, switch, list, and delete branches with clear examples and visual explanations.

git branchgit switchgit checkout -b
7 min
BranchingIntermediate

git merge vs git rebase: When to Use Each

Understand the difference between merge and rebase, when to use each strategy, and how to handle conflicts. Includes visual commit graph examples.

git mergegit rebasegit rebase -i
10 min
BasicsBeginner

git init: Creating Your First Repository

Learn how to create a Git repository from scratch. Understand what git init does, what's inside the .git folder, and how to make your first commit.

git initgit addgit commit
6 min

© 2026 Komitly

support@komitly.com
BlogPricingChangelogTermsPrivacy

What is a merge conflict?

A merge conflict happens when Git cannot automatically combine changes from two branches because both branches modified the same lines in the same file. Git does not know which version to keep, so it pauses the merge and asks you to resolve it manually.

Conflicts are a normal part of collaboration. They are not errors — they are Git saying "I found two different edits to the same code and I need a human to decide what the final version should look like." Once you learn the pattern, resolving them takes seconds.

Merge conflicts are one of the biggest fears for Git beginners. The good news: they follow a simple, predictable pattern. After resolving a few, they stop being scary and become routine.

How conflicts happen

Conflicts occur when two branches diverge — they both have commits that the other does not — and those commits touch the same lines. Here is a typical scenario:

  1. You and a teammate both start from the same commit on main.
  2. Your teammate fixes accessibility in the Header component and pushes to main.
  3. Meanwhile, on your feature/redesign branch, you restyle the same Header component.
  4. When you try to merge feature/redesign into main, Git sees that both branches modified the same lines and raises a conflict.

Here is what the commit graph looks like — two branches that have diverged from a common ancestor:

Komitly - Commit Graph (diverged branches)
e7b8c9dUpdate header stylingfeature/redesign
d6a7b8cFix header accessibilitymain
c5d6e7fAdd header component
b4c5d6eInitial commit

When you run git merge, Git attempts to combine the two branches automatically. If it cannot resolve every overlap, it stops and reports the conflict:

Terminal

Notice that Git tells you exactly which files have conflicts. The merge is paused, not failed — your working tree contains the conflict markers, and Git is waiting for you to fix them.

What does NOT cause conflicts

It is important to understand that not all merges produce conflicts. Git can automatically resolve most situations:

  • Two branches editing different files — no conflict. Git combines both sets of changes.
  • Two branches editing different parts of the same file — no conflict. Git merges both hunks independently.
  • One branch adds a file, the other does not touch it — no conflict.

Conflicts only arise when both branches modify the same lines (or one deletes a file the other modified).

Reading conflict markers

When Git encounters a conflict, it inserts special markers directly into the file. Open the conflicting file and you will see something like this:

src/components/Header.tsx (with conflict markers)
import { useState } from 'react';

export default function Header() {
<<<<<<< HEAD
  return (
    <header className="header" role="banner">
      <nav aria-label="Main navigation">
        <a href="/" className="logo">My App</a>
      </nav>
    </header>
  );
=======
  const [menuOpen, setMenuOpen] = useState(false);

  return (
    <header className="header-redesign">
      <div className="logo-wrapper">
        <a href="/">My App</a>
      </div>
      <button onClick={() => setMenuOpen(!menuOpen)}>
        Menu
      </button>
    </header>
  );
>>>>>>> feature/redesign
}

There are three markers to look for:

  • <<<<<<< HEAD — Marks the beginning of your version (the branch you are currently on).
  • ======= — The divider between the two versions.
  • >>>>>>> feature/redesign — Marks the end of their version (the branch being merged in).

Here is how the two sides look in a diff view:

Komitly - Conflict View
src/components/Header.tsx
<<<<<<< HEAD (yours — the branch you are on)
1- <header className="header" role="banner">
2- <nav aria-label="Main navigation">
3- <a href="/" className="logo">My App</a>
4- </nav>
5- </header>
======= (divider)
1+ <header className="header-redesign">
2+ <div className="logo-wrapper">
3+ <a href="/">My App</a>
4+ </div>
5+ <button onClick={() => setMenuOpen(!menuOpen)}>
6+ Menu
7+ </button>
8+ </header>
>>>>>>> feature/redesign (theirs — the branch being merged)
Code outside the conflict markers was merged automatically and is fine. You only need to deal with the sections between <<<<<<<< and >>>>>>>.

Multiple conflicts in one file

A single file can have more than one conflict zone. Each zone has its own set of <<<<<<<< / ======= / >>>>>>> markers. You must resolve every zone before the file is considered clean.

Multiple conflicting files

A merge can also produce conflicts in more than one file. Use git status to see the full list:

Terminal
$ git status
On branch main
You have unmerged paths.
Unmerged paths:
both modified: src/components/Header.tsx
both modified: src/styles/header.css
both modified: src/utils/navigation.ts
Changes to be committed:
modified: src/App.tsx
modified: package.json

Files under "Unmerged paths" need to be resolved. Files under "Changes to be committed" were merged automatically and are ready.

Resolving conflicts step by step

Resolving a conflict always follows the same five-step pattern. Regardless of the complexity, the process is identical:

Terminal
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/components/Header.tsx
Conflict markers explained
<<<<<<< HEAD
  // Everything between <<<<<<< and =======
  // is YOUR version (the branch you are on)
=======
  // Everything between ======= and >>>>>>>
  // is THEIR version (the branch you are merging in)
>>>>>>> feature/redesign
src/components/Header.tsx (resolved)
import { useState } from 'react';

export default function Header() {
  const [menuOpen, setMenuOpen] = useState(false);

  return (
    <header className="header" role="banner">
      <nav aria-label="Main navigation">
        <a href="/" className="logo">My App</a>
      </nav>
      <button
        onClick={() => setMenuOpen(!menuOpen)}
        aria-expanded={menuOpen}
      >
        Menu
      </button>
    </header>
  );
}
Terminal
# Verify no markers remain
$ grep -n '<<<<<<\|======\|>>>>>>' src/components/Header.tsx
# No output = no markers left ✓
Terminal
$ git add src/components/Header.tsx
$ git commit -m "Merge feature/redesign: combine new menu with accessibility"
[main 7a8b9c0] Merge feature/redesign: combine new menu with accessibility

After the merge commit, your graph shows the two branches joined together:

Komitly - Commit Graph (after merge)
7a8b9c0Merge feature/redesignmain
e7b8c9dUpdate header stylingfeature/redesign
d6a7b8cFix header accessibility
c5d6e7fAdd header component
b4c5d6eInitial commit

Aborting a merge

If you are in the middle of resolving conflicts and decide you are not ready, you can cancel the entire merge and go back to the state before it started:

Terminal
# Changed your mind? Abort the entire merge
$ git merge --abort
$ git status
On branch main
nothing to commit, working tree clean
$ git merge --abort

Hover over each part to see what it does

This is completely safe — all conflict markers and partial resolutions are discarded, and your branch is restored to its pre-merge state. The other branch is not affected.

Resolving conflicts in Komitly

Resolving conflicts in a text editor works, but it requires you to mentally parse the markers and piece together the right version. Komitly provides a dedicated visual 3-way merge editor that makes the process dramatically easier.

The 3-way merge editor

When Komitly detects conflicting files, it opens a three-panel layout:

  • Left panel — Yours (HEAD): The version on your current branch.
  • Right panel — Theirs (incoming): The version from the branch being merged.
  • Bottom panel — Result: The merged output. This is what will be saved to the file.

For each conflict zone, you have one-click resolution buttons:

  • Accept Yours — Keep your version and discard theirs.
  • Accept Theirs — Keep their version and discard yours.
  • Accept Both — Include both versions one after the other.

You can also edit the result panel directly for cases where you need to write a custom resolution that combines parts of both versions (like in our Header example).

Here is what the resolved version looks like — combining the accessibility attributes from one branch with the menu button from the other:

Komitly - Resolved Diff
src/components/Header.tsx (resolved)
@@ resolved: keeping both contributions @@
11 const [menuOpen, setMenuOpen] = useState(false);
22
3+ <header className="header" role="banner">
4+ <nav aria-label="Main navigation">
5+ <a href="/" className="logo">My App</a>
6+ </nav>
7+ <button
8+ onClick={() => setMenuOpen(!menuOpen)}
9+ aria-expanded={menuOpen}
10+ >
11+ Menu
12+ </button>
13+ </header>

Conflict prediction

One of Komitly's most powerful features is conflict prediction. Before you even start a merge or rebase, Komitly analyzes both branches and tells you which files will conflict. This lets you prepare ahead of time or choose a different strategy entirely.

The merge preview dialog shows a list of files that will be affected, with conflict warnings highlighted in red. You can review the potential conflicts, decide whether to proceed, or abort before anything happens.

Conflicts during interactive rebase

Conflicts can also happen during a rebase. The interactive rebase editor in Komitly includes real-time conflict prediction — as you reorder, squash, or drop commits, Komitly warns you which steps might produce conflicts. If a conflict does occur, the same 3-way merge editor opens, and you resolve it the same way.

In Komitly, you never have to manually search for <<<<<<<< markers. The 3-way merge editor shows both versions side by side with one-click resolution buttons. Combined with conflict prediction, you can anticipate and resolve conflicts faster than ever.

Preventing conflicts

While conflicts are unavoidable in active teams, you can significantly reduce their frequency with a few habits:

  • Pull frequently. The longer your branch lives without syncing, the more it diverges from the main branch. Pull from main at least once a day when working on a long-lived branch.
  • Keep branches short-lived. Merge your feature branches back quickly. A branch that lives for a week is far more likely to conflict than one that lives for a day.
  • Communicate with your team. If two people are editing the same file, a quick message can save a lot of conflict resolution. Code ownership and task division help.
  • Split large files. A 500-line file is a conflict magnet. Smaller, focused files reduce the chance of two people editing the same one.
  • Use Komitly's conflict prediction. Before merging, check the merge preview to see if conflicts are expected. If they are, you can coordinate with your team or resolve them when you are ready, not when you are in the middle of something else.

Summary

Merge conflicts are a normal part of collaborative development. They follow a predictable pattern, and once you learn the steps, they become routine rather than frightening. Here is a quick recap:

  • Conflicts happen when two branches modify the same lines in the same file.
  • Git marks conflicts with <<<<<<< HEAD, =======, and >>>>>>> branch-name markers.
  • To resolve: open the file, choose which version to keep (or combine both), remove the markers, stage with git add, and commit.
  • Use git merge --abort to cancel a merge and start over.
  • Komitly's 3-way merge editor shows both versions side by side with Accept Yours, Accept Theirs, and Accept Both buttons — no marker parsing required.
  • Komitly's conflict prediction warns you about potential conflicts before you start a merge or rebase.
  • Prevent conflicts by pulling frequently, keeping branches short-lived, and communicating with your team.

With conflicts demystified, you are ready to collaborate confidently. Next, learn how to put this all together in a complete workflow with your first pull request.