GitMuninnGitMuninn
← Back to the blog

How to resolve Git merge conflicts without fear

Why conflicts happen, how to read the markers, step-by-step resolution in a merge and in a rebase, tools that help, and habits that lead to fewer conflicts.

You run git merge and the terminal replies: CONFLICT (content): Merge conflict in src/api.ts. Relax. It's not an error. Git is asking you to make a decision it can't make on its own.

In this guide you'll learn why conflicts happen, how to read what Git wrote into the file, how to resolve a conflict in a merge and in a rebase, which tools help, and what to do day to day to get fewer conflicts.

Why conflicts happen

Git combines changes on its own when they touch different parts of a file. If you changed line 10 and a teammate changed line 80, the merge goes through without asking anything.

A conflict shows up in three situations:

  • Both branches changed the same lines, or lines very close to each other.
  • One side deleted a file that the other side edited (deleted by them or deleted by us).
  • Both sides created or renamed the same file in different ways.

In these cases there is no correct automatic answer. Someone who knows the code has to look and decide.

How to read the markers

Inside the file, Git marks the disputed section like this:

<<<<<<< HEAD
const timeout = 30;
=======
const timeout = 60;
>>>>>>> feature/retry
  • Between <<<<<<< HEAD and ======= is your side, meaning the branch you're on.
  • Between ======= and >>>>>>> feature/retry is the side that came in with the merge.
  • Your job is to leave only the final result: one side, the other, or a combination of both. Then delete the markers.

Here's a tip that helps a lot: turn on the zdiff3 style. With it, Git also shows what the section looked like before either side changed it, which makes it clear what each side meant to do.

git config --global merge.conflictStyle zdiff3
<<<<<<< HEAD
const timeout = 30;
||||||| base
const timeout = 10;
=======
const timeout = 60;
>>>>>>> feature/retry

Now you can see the original value was 10. You raised it to 30 and your teammate raised it to 60. The decision gets much easier.

Step by step: resolving a merge

  1. Run git status to see the conflicted files. They show up as both modified.
  2. Open each file, decide each block, and remove the markers.
  3. Build and run the tests. A merge without markers can still break the code, for example when one side renamed a function that the other side started using.
  4. Mark each file as resolved with git add <file>.
  5. Finish with git commit. Git already suggests a merge message.

If the whole file should stay as it is on one side, you don't need to edit block by block:

git checkout --ours src/api.ts     # keep your side
git checkout --theirs src/api.ts   # keep the incoming side
git add src/api.ts

If things get out of hand, git merge --abort puts everything back to how it was before the merge. You can start over calmly.

Conflicts during a rebase

In a rebase, Git replays your commits one by one on top of another branch. That's why a conflict can show up more than once, once for each commit that touches the same lines.

The flow is similar, with one important difference: in a rebase, ours and theirs are swapped. --ours becomes the target branch, for example main, and --theirs is your commit that's being replayed.

  1. Resolve the files for the current commit and run git add.
  2. Continue with git rebase --continue.
  3. Repeat until the rebase finishes.
  4. If you'd rather give up, git rebase --abort puts everything back the way it was.

Tools that help

  • git mergetool opens a configured visual tool, such as VS Code, Meld, or KDiff3.
  • git log --merge -p <file> shows only the commits from both sides that touched the conflicted file.
  • git rerere records how you resolved a conflict and reapplies the same resolution if it shows up again. Turn it on with git config --global rerere.enabled true.
  • git diff during a conflict shows only the sections that are still unresolved.

How to get fewer conflicts

  • Bring main into your branch often, not just at the end.
  • Prefer short-lived branches that last days, not weeks.
  • Make small commits focused on one change.
  • Agree on a code formatter with your team, so whitespace and line breaks don't turn into conflicts.
  • Avoid moving a file and editing its contents in the same commit.
  • Talk to your team before touching files everyone edits, such as routes, config files, and dependency lists.

Resolving conflicts in GitMuninn

In GitMuninn, conflicts show up block by block. For each block you pick your side, the incoming side, or both, and you save when the file is resolved, without hunting for markers. The graph shows where each branch came from, which helps you understand the change before you decide. This is included in the Free plan.

See your branches in GitMuninn.

Join the launch list and get 50% off Pro and Business for 12 months.

Plan you are interested in

For macOS, Windows, and Linux. No spam, leave anytime.