Skip to main content
๐Ÿ›ก๏ธ Verified Technical Content: Written by Serhii Hrekov. | Last reviewed & updated in Git: July 21, 2026

Git Merging: How to Resolve Conflicts, Choose Strategies, and Keep Clean History

ยท 11 min read
Serhii Hrekov
Senior Software Engineer & System Architect specializing in Python, Web Systems, Cloud Infrastructure & Automation

The dreaded CONFLICT (content): Merge conflict in file.txt. For many developers, seeing this message triggers an immediate spike in heart rate. It feels like you broke something.

Take a deep breath. You didn't break anything. A merge conflict is simply Git throwing its hands up and saying, "Hey, two people changed the exact same line of code, and I am not smart enough to guess which one is right. I need a human."

Here is how to read the Matrix, resolve the conflict, and get on with your day without losing your mind.

The Anatomy of a Conflictโ€‹

When a conflict happens, Git physically injects "Conflict Markers" straight into your code. To fix the conflict, you literally just delete the markers and leave the code you want to keep.

Here is what a raw conflict looks like inside your file:

<<<<<<< HEAD
const serverPort = 8080;
=======
const serverPort = 3000;
>>>>>>> feature-new-server

Decoding the Markersโ€‹

  • <<<<<<< HEAD : This is the start of your current changes (the branch you are currently standing on).
  • ======= : This is the divider. It separates your changes from the incoming changes.
  • >>>>>>> branch-name : This is the end of the incoming changes (the branch you are trying to merge in).

The 3-Step Resolution Processโ€‹

When your terminal turns red with conflicts, follow this exact checklist.

Step 1: Find the Battlegroundsโ€‹

Git will usually tell you which files are conflicted, but if you clear your terminal and lose the message, just type:

git status

Look for the files listed under "Unmerged paths". These are the files containing the conflict markers.

Step 2: Make the Choice (The Edit)โ€‹

Open the conflicted files in your code editor. You have three choices for every conflict:

  1. Accept Current (HEAD): Keep your code, delete their code.
  2. Accept Incoming: Keep their code, delete your code.
  3. Accept Both / Combine: Rewrite the block of code to include elements of both.

To resolve it manually, you just delete the weird Git symbols and leave the correct code.

Before:

<<<<<<< HEAD
const serverPort = 8080;
=======
const serverPort = 3000;
>>>>>>> feature-new-server

After (Decided to keep 3000):

const serverPort = 3000;

Step 3: Seal the Dealโ€‹

Once you have removed all the <====> markers from all the files, you need to tell Git you are finished.

# 1. Stage the resolved files
git add .

# 2. Complete the merge (Git will auto-generate a merge message for you)
git commit

Pro-Tips for Keeping Your Sanityโ€‹

1. Use a Visual IDE (Stop Doing This in Notepad)โ€‹

If you are using a modern editor like VS Code, IntelliJ, or WebStorm, you don't even have to manually delete the markers.

When you open a conflicted file, the editor will highlight the block in neon colors and give you clickable buttons that say: [Accept Current Change] | [Accept Incoming Change] | [Accept Both Changes]

Clicking one of those buttons automatically cleans up the markers for you.

2. The Panic Buttonโ€‹

If you start trying to resolve a massive conflict, get confused, accidentally delete half the file, and feel like you are going to cry, stop. You can always rewind time and abort the merge entirely to try again later.

git merge --abort

(This puts your repository exactly back to how it was 5 seconds before you typed git merge.)


Conflict Resolution Cheat Sheetโ€‹

Command / ActionWhat it does
git statusLists all files currently containing conflict markers.
<<<<<<< HEADShows the code you currently have.
>>>>>>> branchShows the code someone else wrote.
git add <file>Tells Git: "I have manually fixed the markers in this file."
git merge --abortThe emergency undo switch.

Sourcesโ€‹

  • [1.1] Git SCM Docs: Basic Merge Conflicts - The official documentation on reading markers.
  • [2.1] VS Code Docs: Merge Conflicts - How to use Microsoft's built-in 3-way merge editor.

Merge Strategies: Squash, True Merge, and Fast-Forwardโ€‹

Before you merge, you need to decide how you want your history to look. There are three main ways to combine a feature branch into main.

The Squash Merge (Industry Standard)โ€‹

Instead of bringing over all of your tiny "wip" and "fix typo" commits, a squash merge crushes them all into one single, clean commit on the main branch.

  • Best for: Feature branches and bug fixes.
  • Why it works: It keeps the main branch incredibly clean. Every commit on main represents one complete, working feature.

The True Merge (--no-ff)โ€‹

Creates a dedicated "Merge Commit" that links the two branches together, preserving every single individual commit.

  • Best for: Massive, multi-developer epics where the historical context matters.
  • Why it's risky: It creates the classic "Git Spaghetti" graph if overused.

The Fast-Forward (--ff-only)โ€‹

If nothing has changed on main since you started your branch, Git just moves the main pointer forward.

  • Best for: Small, local, single-person projects.

How to Merge Locally (CLI)โ€‹

# 1. Update your local main
git checkout main
git pull origin main

# 2. (Optional) Rebase your feature branch first
git checkout your-feature-branch
git rebase main

# 3. Switch back to main
git checkout main

# 4. Execute the Merge (Choose ONE)

# Option A: The Squash Merge (Recommended)
git merge --squash your-feature-branch
git commit -m "feat: added new login dashboard"

# Option B: The True Merge
git merge --no-ff your-feature-branch

# 5. Push
git push origin main
StrategyCommandResult on main HistoryWhen to use it?
Squashmerge --squash1 Clean Commit90% of your daily Pull Requests.
True Mergemerge --no-ffAll Commits + 1 Merge CommitLarge collaborative feature branches.
Fast-Forwardmerge --ff-onlyAll Commits (Linear)Quick local updates.

Rebase vs. Merge: When to Choose Eachโ€‹

Neither rebase nor merge is inherently "better"; they are different tools for different purposes.

The Case for rebase: The Clean Historyโ€‹

git rebase maintains a clean, linear, and easy-to-read commit history. It makes it look as if a feature was developed directly on top of the main branch.

  • Avoids Merge Commits: Creates a linear history that is easier to navigate with git log and git bisect.
  • Use With: Local, private feature branches that have not been shared.

The Case for merge: The Accurate Historyโ€‹

git merge preserves an accurate and chronological record. It maintains the true history of when and how branches diverged and came back together.

  • Non-Destructive: Doesn't rewrite history; simply adds a new commit.
  • Use With: Public, shared, or long-running branches.
Featuregit rebasegit merge
HistoryClean, linear, and rewrittenAccurate, chronological, preserves merge points
SafetyRisky on shared branchesSafe for all branches
Use CaseLocal, private feature branchesPublic, shared, or long-running branches
Commit GraphFlat, no merge commitsCan be cluttered with merge commits

Additional Sourcesโ€‹