Git/
Lesson

You're merging your feature branch into main, feeling good about your work, when suddenly Git throws up its hands and says "nope." Red text everywhere. Files marked as conflicted. Your heart sinks.

Take a deep breath. Merge conflicts look scary, but they're actually Git protecting you from making a mistake. When Git encounters conflicting changes, it stops and asks you to decide what the final code should look like.

Why conflicts happen (and why they're good)

Imagine you and a teammate both edited the same paragraph of a document. You changed it one way, they changed it another. If a computer automatically picked one version, someone would lose work. That's exactly what Git refuses to do.

Conflicts happen when:

  • The same line is modified differently in both branches
  • One branch deleted a file that another branch modified
  • One branch deleted lines that another branch changed
  • BinaryWhat is binary?A ready-to-run file produced by the compiler. You can send it to any computer and it just works - no install needed. files (images, PDFs) changed in both branches
main branch:       const theme = "dark";

feature-A:         const theme = "light";

feature-B:         const theme = "auto";

Git: "I see three different values for 'theme'. You decide."
AI pitfall
When AI tools encounter merge conflicts, they often resolve them poorly. Copilot might suggest "Accept Current Change" for every conflict without understanding the context. ChatGPT might generate a resolution that compiles but silently deletes your teammate's logic. Always read both sides of a conflict carefully and understand what each branch was trying to do before resolving.
Conflict frequency
In healthy teams, conflicts are common but small. If you're having massive conflicts that take hours to resolve, it's usually a sign that branches are living too long or the team isn't communicating enough. Small, frequent merges = small, manageable conflicts.
02

Reading conflict markers

When Git hits a conflict, it modifies the file in question to show you both versions. These are called conflict markers, and they look intimidating at first but follow a simple pattern:

<<<<<<< HEAD
const color = "blue";     // This is what's in your current branch
=======
const color = "red";      // This is what's in the branch you're merging
>>>>>>> feature-login

Let's break down these markers:

MarkerMeaning
<<<<<<< HEADStart of your current branch's version
=======Separator between the two versions
>>>>>>> feature-loginEnd of the incoming branch's version

HEAD always refers to the branch you're currently on (the one you're merging into). The branch name after the arrows (feature-login in this example) is the branch being merged.

Here's a more realistic example with multiple conflict regions:

function getUserData() {
<<<<<<< HEAD
  return fetch('/api/user').then(r => r.json());
=======
  const response = await fetch('/api/user');
  return await response.json();
>>>>>>> feature-login
}

function formatName(name) {
<<<<<<< HEAD
  return name.toUpperCase();
=======
  return name.trim().toUpperCase();
>>>>>>> feature-login
}

Notice there are two separate conflict regions. Each one needs to be resolved independently.

03

The conflict resolution workflow

Resolving conflicts is a methodical process. Follow these steps every time:

Step 1: Understand what's conflicted

First, see the scopeWhat is scope?The area of your code where a variable is accessible; variables declared inside a function or block are invisible outside it. of the problem:

git status

You'll see something like:

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/utils.js
  both modified:   src/components/Header.js
  deleted by us:   old-styles.css

Step 2: Open each conflicted file

For each file listed, open it in your editor. Search for the conflict markers (<<<<<<<).

Step 3: Decide and edit

This is the critical part. You have three choices for each conflict:

Keep your version (HEADWhat is head?A special pointer in Git that indicates the commit you are currently working on - usually the tip of the active branch.):

const color = "blue";

Keep their version (incoming):

const color = "red";

Combine both versions:

const color = "purple";   // merge the ideas

Most of the time, you'll want a combination. Take this example:

// Conflict:
<<<<<<< HEAD
function greet(name) {
  console.log("Hello, " + name);
}
=======
function greet(user) {
  console.log(`Hello, ${user}!`);
}
>>>>>>> feature-login

// Resolution - combine the parameter name and template literal:
function greet(name) {
  console.log(`Hello, ${name}!`);
}

Step 4: Remove all conflict markers

This is crucial, if you leave the markers in, your code won't work:

// BAD - markers still present:
<<<<<<< HEAD
const value = 10;
=======
const value = 20;
>>>>>>> feature-branch

// GOOD - clean resolution:
const value = 15;

Step 5: Test your changes

Before you mark the conflict as resolved, test that your code actually works:

npm test          # Run your test suite
npm run build     # Make sure it compiles
npm run lint      # Check for syntax errors

Step 6: Stage and commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed.

Once the file is fixed and tested:

git add src/utils.js
git add src/components/Header.js

# After all conflicts are resolved
git commit -m "Merge feature-login, resolve API conflicts"
04

Aborting when you're overwhelmed

Sometimes you start resolving conflicts and realize you're in over your headWhat is head?A special pointer in Git that indicates the commit you are currently working on - usually the tip of the active branch.. You can abort the merge entirely:

git merge --abort

This returns your repositoryWhat is repository?A project folder tracked by Git that stores your files along with the complete history of every change, inside a hidden .git directory. to the exact state it was in before the merge started. No harm done.

Don't be afraid to abort. It's better to abort and approach the problem differently than to force a merge resolution you're not confident about.
05

Tools that help with conflicts

ToolTypeBest for
VS CodeIDEBuilt-in merge conflict UI with click-to-resolve buttons
IntelliJ/WebStormIDEPowerful 3-way merge view
GitKrakenGit GUIVisual conflict resolution
git mergetoolCLILaunch your configured merge tool

VS Code shows conflict buttons directly in the editor:

[Accept Current] [Accept Incoming] [Accept Both] [Compare]

Clicking these buttons resolves the conflict instantly without you manually editing markers.

06

Prevention: avoiding conflicts in the first place

While conflicts are inevitable, you can reduce them:

Pull before you push. Always pull the latest main before starting work and before merging.

Communicate with your team. If you know someone is working on the same files, coordinate.

Smaller branches, more frequent merges. A branch that lives for two weeks will have more conflicts than one that lives for two days.

Use code ownership patterns. If possible, have clear ownership of different parts of the codebase.

07

Quick reference

CommandWhat it doesWhen to use it
git statusSee conflicted filesFirst step after conflict
git diffSee conflict detailsUnderstand the problem
git add fileMark file as resolvedAfter editing
git commitComplete the mergeAfter all files resolved
git merge --abortCancel the mergeStart over
git mergetoolOpen visual merge toolComplex conflicts
javascript
# When you have a conflict, first see what files are affected
git status

# After editing the file to fix conflicts, stage it
git add conflicted-file.js

# Complete the merge
git commit -m "Resolve merge conflicts"

# Or abort if you want to start over
git merge --abort