Skip to main content
    Courses/Git/Resolving Merge Conflicts

    Lesson 4 • Intermediate

    Resolving Merge Conflicts 🌿

    By the end of this lesson you'll be able to read Git's conflict markers, resolve a clash by hand, finish the merge with git add and git commit, bail out safely with git merge --abort, and structure your work so conflicts rarely happen at all.

    What You'll Learn

    • Explain exactly what makes Git raise a merge conflict
    • Read the three conflict markers (<<<<<<<, =======, >>>>>>>)
    • Resolve a conflict by editing the file and removing all markers
    • Finish the merge with git add and git commit
    • Bail out of a bad merge instantly with git merge --abort
    • Prevent most conflicts with small, frequent merges and communication

    💡 Real-World Analogy

    A merge conflict is like two people editing the same sentence of a shared document at the same time. When their edits come together, the document can't show both, so it asks: "Alice wrote blue but Bob wrote green — which should I keep?" Git is exactly that careful editor. It happily combines edits to different sentences on its own, but when two edits land on the same line it stops and lets you, the human, make the final call. A conflict isn't an error or a bug — it's Git refusing to silently throw away someone's work.

    1️⃣ Why Conflicts Happen

    Git is very good at merging changes automatically. A conflict happens only when two branches modify the exact same lines of the same file. Different files, or different lines of the same file? Git merges them for you with no fuss. Read this worked example, then run a merge and watch Git stop.

    Worked example: what causes a conflict
    # A conflict happens when two branches change the SAME lines of the SAME
    # file, so Git can't decide which version is correct. It refuses to guess
    # and hands the decision to you.
    #
    #   main   had:  color: blue;
    #   you    made: color: red;     (on branch main)
    #   teammate made: color: green; (on branch feature-branch)
    #                                 -> both touch line 5 -> CONFLICT
    #
    # What does NOT conflict (Git merges these for you, no markers):
    #   - different files were modified
    #   - the same file, but different lines
    #   - one branch adds new content, the other leaves that area alone
    #
    # Try to merge a branch that changed the same line and Git stops:
    git merge feature-branch
    Output
    Auto-merging style.css
    CONFLICT (content): Merge conflict in style.css
    Automatic merge failed; fix conflicts and then commit the result.
    Run this in a real Git repo where two branches changed the same line. The CONFLICT line is Git asking for your help, not a crash.

    2️⃣ Reading the Conflict Markers

    When a conflict occurs, Git edits the file and wraps the clashing lines in three markers. Everything between <<<<<<< HEAD and ======= is your version (the branch you're on, called HEAD); everything between ======= and >>>>>>> is theirs (the branch coming in). Lines outside the markers merged cleanly.

    Worked example: a conflicted file
    # When a conflict happens, Git edits the file IN PLACE and inserts three
    # markers around the clashing section. Open style.css and you'll see:
    
    body {
      font-size: 16px;
    <<<<<<< HEAD
      color: red;          # YOUR version  (the branch you are ON, called HEAD)
    =======
      color: green;        # THEIR version (the branch you are merging IN)
    >>>>>>> feature-branch
      margin: 0;
    }
    
    # Read the markers like this:
    #   <<<<<<< HEAD        start of YOUR version (everything above =======)
    #   =======             the dividing line between the two versions
    #   >>>>>>> feature-branch   end of THEIR version (everything below =======)
    #
    # Note: "font-size" and "margin" are OUTSIDE the markers — Git merged those
    # fine. Only the lines Git couldn't reconcile are wrapped.
    This is what the file looks like on disk after a conflict. Open it in any text editor to fix it.

    3️⃣ Resolving by Hand

    Resolving means making a decision and cleaning up. You edit the file to the version you actually want — keep yours, keep theirs, combine both, or write something new — and then delete all three markers. The conflict is "resolved" the moment no markers remain. Here's the same file from above, finished.

    Worked example: the resolved file
    # To resolve, you EDIT the file by hand: pick the version you want (or
    # combine them, or write something new), then DELETE all three markers.
    # Here you decide "green" is correct, so the finished file reads:
    
    body {
      font-size: 16px;
      color: green;        # kept THEIR version; HEAD line + all 3 markers gone
      margin: 0;
    }
    
    # A conflict is "resolved" when NO markers remain. Git doesn't care which
    # side you keep — it only checks that <<<<<<<, =======, and >>>>>>> are gone.
    The whole job is: choose the right content, then make sure no <<<<<<<, =======, or >>>>>>> lines are left.

    Your turn. Below is a conflict in greeting.txt. You've decided the page should greet returning visitors. Replace the ___ with the one line that should remain — and remember, no markers belong in the finished file.

    🎯 Your turn: pick the resolved line
    # 🎯 YOUR TURN — a conflict in greeting.txt. You decide the page should
    # say "Welcome back!" (THEIR version). Write the file with NO markers left.
    
    # The conflicted file currently looks like this:
    #   <<<<<<< HEAD
    #   Hello!
    #   =======
    #   Welcome back!
    #   >>>>>>> feature-greeting
    
    # Replace ___ with the single correct resolved line:
    ___                       # 👉 the one line that should remain (no markers!)
    
    # ✅ Expected resolved greeting.txt:
    #   Welcome back!
    Resolving is a choice: type the single line you want to keep, with every marker deleted.

    4️⃣ Finishing the Merge

    Editing the file isn't quite the end. You have to tell Git the conflict is fixed by staging the file with git add, then complete the merge with git commit. Use git status at any point to see which files are still "both modified".

    Worked example: resolve, stage, and commit
    # The full resolve-a-conflict routine, start to finish.
    
    # 1. A merge triggers a conflict
    git merge feature-auth
    
    # 2. See exactly which files are conflicted ("both modified")
    git status
    
    # 3. Open each file, choose/combine the changes, and remove every
    #    <<<<<<<, =======, and >>>>>>> marker. (VS Code shows clickable
    #    "Accept Current / Incoming / Both Changes" buttons above the markers.)
    code src/App.js
    
    # 4. Stage the resolved file — this is how you tell Git "I fixed it"
    git add src/App.js
    #    For several conflicted files: resolve each, then  git add .
    
    # 5. Finish the merge with a commit (Git pre-fills a merge message)
    git commit -m "Merge feature-auth"
    Output
    Auto-merging src/App.js
    CONFLICT (content): Merge conflict in src/App.js
    Automatic merge failed; fix conflicts and then commit the result.
    
    On branch main
    You have unmerged paths.
      (fix conflicts and run "git commit")
    
    Unmerged paths:
      (use "git add <file>..." to mark resolution)
            both modified:   src/App.js
    
    [main abc1234] Merge feature-auth
    Run these in a real Git repo. Step 4's git add is what flips a file from "conflicted" to "resolved".

    Now you finish a merge. You've already edited config.json and removed every marker — only the two final commands remain. Fill in the blanks.

    🎯 Your turn: finish the merge
    # 🎯 YOUR TURN — you've already edited config.json and deleted every
    # conflict marker. Two commands are left to FINISH the merge.
    
    # 1) Tell Git the conflict in config.json is resolved
    ___ config.json          # 👉 the command that stages a resolved file
    
    # 2) Complete the merge by recording a commit
    git ___ -m "Merge feature-config"   # 👉 the verb that records a commit
    
    # ✅ Expected: git status afterwards shows "working tree clean"
    #    and the merge appears in  git log --oneline
    Two steps close a merge: stage the resolved file, then record a commit.

    5️⃣ The Escape Hatch: git merge --abort

    Sometimes you start a merge and realise it's the wrong branch, or the conflicts are bigger than expected. Don't panic and start deleting markers at random. One command rewinds you to exactly how things were before the merge — like it never happened.

    Worked example: cancel a merge safely
    # Made a mess, or merged the wrong branch? Don't panic and don't start
    # deleting markers blindly. One command rewinds you to BEFORE the merge,
    # as if it never happened — no commits, no half-resolved files:
    git merge --abort
    
    # After aborting, your working tree is clean again:
    git status
    Output
    On branch main
    nothing to commit, working tree clean
    git merge --abort only works while a merge is unfinished (before you commit it). It's completely safe — nothing you'd lose has been saved yet.

    6️⃣ Resolution Tools

    You never have to manage markers in a bare text editor. VS Code recognises conflicts and shows clickable Accept Current Change, Accept Incoming Change, and Accept Both Changes buttons right above each clash, plus a side-by-side comparison. Most editors and IDEs (JetBrains, Sublime) have the same. Git also ships git mergetool, which opens a dedicated three-way merge view. Whatever tool you use, the end state is identical: the right content, and no markers left behind.

    7️⃣ Preventing Conflicts

    The best conflict is one that never happens. Merge from main often so your branch doesn't drift, keep branches small and focused, talk to your team so two people aren't rewriting the same file, and use .gitignore so generated files never collide.

    Worked example: stay in sync and ignore noise
    # The best conflict is one that never happens. Prevention strategies:
    #   - Merge/pull often so your branch never drifts far from main.
    #   - Keep branches small and focused (fewer changes = fewer clashes).
    #   - Communicate so two people don't rewrite the same file at once.
    #   - Don't mix a big refactor and a new feature in one branch/PR.
    #   - Use .gitignore so generated files never cause fake conflicts.
    
    # A simple "stay in sync" routine — pull main into your feature branch:
    git checkout main
    git pull origin main
    git checkout my-feature
    git merge main
    
    # Create a .gitignore so build artefacts are never tracked (and so they
    # never collide on merge):
    cat > .gitignore <<'EOF'
    node_modules/
    dist/
    .env
    .DS_Store
    *.log
    coverage/
    EOF
    git add .gitignore
    git commit -m "Add .gitignore"
    Output
    Already up to date.
    Updating a1b2c3d..e4f5g6h
    Fast-forward
     README.md | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    [my-feature 7h8i9j0] Add .gitignore
     1 file changed, 6 insertions(+)
     create mode 100644 .gitignore
    Run these in a real Git repo. Merging main in little and often means each merge has far less to clash over.

    Common Errors (and the fix)

    • Committing the markers by accident — leaving <<<<<<< / ======= / >>>>>>> in a file breaks your code. Run git diff --check before every merge commit — it lists any leftover markers so you can delete them.
    • Panicking and hacking at a bad merge — if a merge is going wrong, stop. git merge --abort rewinds to before the merge cleanly. That's almost always safer than trying to manually undo a half-resolved mess.
    • Resolving the wrong side — blindly clicking "Accept Current" (or always keeping "mine") can silently throw away a teammate's fix. Read both versions, then choose — or combine them.
    • "fatal: There is no merge to abort" — you've already committed the merge (or there isn't one). To undo a finished merge instead, use git reset --hard HEAD~1 on a local-only merge (with care).
    • "error: Committing is not possible because you have unmerged files" — you tried to commit before resolving. Fix the markers, git add each file, then commit.

    Pro Tips

    • 💡 Search before you commit: git diff --check (or grep your project for <<<<<<<) catches markers you missed.
    • 💡 Resolve, don't rush: a conflict is Git protecting two people's work. Read both sides before choosing.
    • 💡 Abort is free: git merge --abort costs you nothing — practise with it until merges stop feeling scary.
    • 💡 Small and often beats big and rare: frequent small merges create tiny, easy conflicts instead of giant ones.

    📋 Quick Reference

    CommandPurpose
    git merge <branch>Start a merge (may raise a conflict)
    git statusSee which files are conflicted
    git add <file>Mark a resolved file as fixed
    git commitComplete the merge
    git merge --abortCancel an in-progress merge
    git diff --checkWarn about leftover markers
    git mergetoolOpen a visual 3-way merge tool

    Frequently Asked Questions

    Q: What do the <<<<<<<, =======, and >>>>>>> conflict markers mean?

    Git inserts them around code it could not merge. Everything between <<<<<<< HEAD and ======= is your version (the branch you are on). Everything between ======= and >>>>>>> branch-name is their version (the branch you are merging in). To resolve, edit the section to what you want and delete all three marker lines.

    Q: I committed the conflict markers by mistake — how do I fix it?

    Edit the file to remove the leftover <<<<<<<, =======, and >>>>>>> lines, then make a new commit. To catch this before committing, run git diff --check, which flags any leftover markers. Many teams also add a CI check or pre-commit hook that fails if markers are found.

    Q: What does git merge --abort do?

    It cancels the in-progress merge and rewinds your repository to exactly how it was before you ran git merge — no merge commit, no half-resolved files. It is the safe escape hatch whenever a merge goes wrong or you merged the wrong branch. It only works while a merge is unfinished (before you have committed the merge).

    Q: How do I finish a merge once I've resolved the conflicts?

    Stage each resolved file with git add <file> (this marks the conflict as resolved), then run git commit. Git pre-fills a merge commit message for you, so you usually just save and close. After that, git status should report a clean working tree.

    Q: How can I avoid merge conflicts in the first place?

    Pull or merge from main frequently so your branch never drifts far, keep branches small and focused, and communicate so two people don't edit the same file at once. Avoid mixing big refactors with feature work, and use .gitignore so generated files (like node_modules or build output) never collide.

    Mini-Challenge: Resolve a Real Conflict

    No blanks this time — just a brief and an outline. Reproduce a real conflict in your own terminal and take it all the way to a clean merge. This is the exact loop you'll run on real projects.

    🎯 Mini-Challenge: create, then resolve, a conflict
    # 🎯 MINI-CHALLENGE: resolve a real conflict end to end.
    # In your own terminal, reproduce and fix a conflict:
    #
    # 1. Make a repo and an initial commit on main with a file note.txt
    #    containing one line:  Draft v1
    # 2. Create a branch "edit-a", change the line to  Final A, commit.
    # 3. Switch back to main, change the SAME line to  Final B, commit.
    # 4. Merge edit-a into main  -> Git reports a CONFLICT in note.txt.
    # 5. Open note.txt, decide the line should read  Final B,
    #    delete all three markers, then stage and commit to finish.
    #
    # ✅ Expected: after the merge commit, git status is clean and note.txt
    #    contains exactly one line:  Final B
    #    (Tip: if you get stuck, git merge --abort rewinds and you can retry.)
    
    # your commands here
    Work through it in your own terminal. If you get stuck, git merge --abort rewinds so you can try again.

    🎉 Lesson Complete

    • ✅ A conflict means two branches changed the same lines of the same file
    • <<<<<<< HEAD=======>>>>>>> wrap your version and theirs
    • ✅ Resolve by editing to the content you want and deleting all three markers
    • ✅ Finish with git add then git commit; check with git status
    • git merge --abort safely rewinds a merge that's going wrong
    • ✅ Small, frequent merges plus good communication prevent most conflicts
    • Next lesson: Git Workflows and Best Practices — how real teams branch, review, and ship

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service

    Install LearnCodingFast

    Learn faster with the app on your home screen.