Suggest an editImprove this articleRefine the answer for “How to resolve merge conflicts in Git?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Merge conflict** - a state where Git cannot auto-combine two branches that changed the same lines differently. It marks each clash with `<<<<<<<`, `=======`, `>>>>>>>`. Edit the file, remove all three markers, write the resolved code, then `git add <file>` and `git commit`. **Key:** run `git status` after merging to confirm no files remain unresolved.Shown above the full answer for quick recall.Answer (EN)Image**Merge conflict** - a state where Git cannot auto-combine two branches because both modified the same lines differently, so it stops and asks you to decide. ## Theory ### TL;DR - Two chefs editing the same recipe line: one writes "1 tsp salt", the other "2 tsp". Git stops and asks you to pick or blend. - Git marks conflicts with `<<<<<<<`, `=======`, `>>>>>>>` and pauses until you fix them manually. - After editing: `git add <file>`, then `git commit` (or `git rebase --continue` if rebasing). - `git merge --abort` cancels mid-merge and restores both branches to their previous state. - `git mergetool` opens a visual 3-pane editor if you prefer that over editing raw markers. ### Quick example ```bash # main has: price: 10 # feature branch changed it to: price: 12 # main also changed it to: price: 15 git checkout main git merge feature # CONFLICT (content): Merge conflict in file.txt # file.txt now shows: <<<<<<< HEAD price: 15 ======= price: 12 >>>>>>> feature # Edit file.txt: remove all three markers, write the right value: price: 15 + tax (12 base) git add file.txt git commit -m "Merge with tax adjustment" ``` You removed all three markers and wrote clean code. That is the whole loop. ### How Git finds the conflict Git runs a three-way merge: it compares your branch (HEAD), the incoming branch, and their common ancestor via `git merge-base`. If only one side changed a line, Git takes that change automatically. If both sides changed the same line differently, Git cannot decide. So it stops, writes conflict markers into the file, and waits. The markers show exactly what each side wrote: - `<<<<<<< HEAD` to `=======` is your current branch - `=======` to `>>>>>>> branch-name` is the incoming branch After you edit and stage the file, the index holds the resolved version. The commit finalizes it. ### When to use which approach - Single file, few conflicts: open in your editor, fix manually, `git add`, `git commit`. - Many files or complex diffs: `git mergetool` with a visual tool like Meld or VS Code. Three panes side by side: base (ancestor), ours, theirs. - Changed your mind mid-resolve: `git merge --abort` resets everything back. Safe to run at any point before the final commit. - Binary files (images, compiled assets): Git cannot merge them. Use `git checkout --ours file.png` or `git checkout --theirs file.png` to pick one version explicitly. - Conflicts during [git rebase](/questions/git-rebase): same markers, but you resolve per commit and run `git rebase --continue` after each one instead of `git commit`. ### Configure diff3 for more context By default the conflict block shows only two sides. Run this once: ```bash git config --global merge.conflictstyle diff3 ``` Now the conflict block adds a third section showing what the common ancestor had. That context often makes it obvious which side is more correct without reading full branch history. ### Common mistakes **Committing without staging first.** ```bash # Wrong - after editing conflicted.js: git commit -m "fixed" # Error: nothing to commit # Right: git add conflicted.js git commit -m "Resolve price conflict" ``` Git needs the staged version to know the conflict is resolved. Without `git add`, it does not know you finished. **Picking one side without reading both.** If a teammate fixed a bug on their branch and you blindly take your version with `git checkout --ours`, you lose their fix. Read both sides. `git diff HEAD file.js` shows what your branch actually has. **Leaving marker characters in the code.** `<<<<<<< HEAD` is plain text. If it ends up in your JavaScript or JSX, the app breaks with a syntax error. After resolving, do a quick search for `<<<<<<<` in the file to confirm all markers are gone. I have seen this slip through code review more times than I would expect. **Forgetting `git status` after a multi-file merge.** Git lists every unresolved file under "both modified". Fix one file, forget to check, commit without it, and now your next `git status` has unresolved files blocking further work. **Using `git merge --continue` without staging.** `--continue` checks the index for staged resolutions. If nothing is staged, it throws an error. Stage first, then continue. ### Real-world usage - React / Next.js: `package.json` dependency conflicts during PR merges are the most common case across teams. - Node/Express: two developers adding route handlers to `app.js` at the same location. - Kubernetes: `deployment.yaml` where ops edits resource limits and dev edits the image tag on the same lines. - Monorepos: lock files (`package-lock.json`, `yarn.lock`) conflict on almost every merge. Most teams skip manual resolution and just regenerate the file after merging. - Linux kernel contributions: `git mergetool` with vimdiff for large patch sets across hundreds of files. On shared branches, use [git merge](/questions/git-merge) to preserve history. If you are working alone on a feature branch, `git rebase main` gives a clean linear history and avoids a merge commit. ### Follow-up questions **Q:** What is the difference between a merge conflict and a rebase conflict? **A:** The conflict markers look identical, but the timing differs. A merge resolves all conflicts in one commit. A rebase replays each commit on top of the target branch, so you may hit conflicts once per commit and run `git rebase --continue` after each one. **Q:** How do you prevent conflicts in a team? **A:** Short, frequently merged branches. `git pull --rebase` daily so your branch stays close to main. Trunk-based development removes long-lived branches entirely, which cuts conflict frequency more than any other single practice. **Q:** What does `git mergetool` do that manual editing does not? **A:** It opens a visual diff with three panes: ancestor, your version, incoming version. You pick hunks or type the merged result in a fourth output pane. Configure it with `git config merge.tool meld` or `git config merge.tool vscode`. **Q:** How do you handle a conflict in a binary file like an image? **A:** Git marks it as unmergeable. Pick one version explicitly: `git checkout --ours logo.png` or `git checkout --theirs logo.png`, then `git add logo.png` and commit. **Q:** (Senior) How does `merge.conflictstyle=diff3` help, and when does Git's rename detection fail? **A:** `diff3` adds the ancestor version inside the conflict block, giving context to understand why each side changed. Rename detection fails when file similarity drops below 50% after edits. Git then treats the file as deleted on one branch and new on the other, producing a "modify/delete" conflict. Fix it manually: `git rm file1.txt`, apply edits to the renamed file, `git add file2.txt`, commit. ## Examples ### Basic: single-line conflict ```bash # main branch has: echo "version: 1.0" > app.txt git commit -am "initial version" # feature branch changes to 2.0 git checkout -b feature echo "version: 2.0" > app.txt git commit -am "update version" # main independently changes to 1.5 git checkout main echo "version: 1.5" > app.txt git commit -am "patch version" git merge feature # CONFLICT (content): Merge conflict in app.txt # app.txt now shows: <<<<<<< HEAD version: 1.5 ======= version: 2.0 >>>>>>> feature # Pick the right one, remove all markers: echo "version: 2.0" > app.txt git add app.txt git commit -m "Resolve version conflict: take 2.0" ``` Both branches edited the same line. You read both, decided 2.0 is correct, removed markers, staged, committed. ### Intermediate: React component with multiple props ```jsx // src/App.js on main - added role display: const App = () => <div>{user.name} ({user.role})</div>; // feature branch added email: const App = () => <div>{user.name} - {user.email}</div>; ``` After `git merge feature`: ```jsx <<<<<<< HEAD const App = () => <div>{user.name} ({user.role})</div>; ======= const App = () => <div>{user.name} - {user.email}</div>; >>>>>>> feature ``` Both changes are valid. Combine them: ```jsx const App = () => ( <div>{user.name} ({user.role}) - {user.email}</div> ); ``` ```bash git add src/App.js git commit -m "Merge feature: show role and email" ``` Run the app after committing. A JSX syntax error at this point almost always means a marker character survived in the file. ### Advanced: rename plus edit conflict ```bash # main renames file1.txt to file2.txt git mv file1.txt file2.txt git commit -m "rename file1 to file2" # feature branch edited file1.txt before the rename was merged git checkout -b feature main~1 echo "new content" >> file1.txt git commit -am "update file1" git checkout main git merge feature # CONFLICT (modify/delete): file1.txt deleted in HEAD and modified in feature. ``` Git's rename detection uses a 50% similarity threshold. When file1.txt has heavy edits on the feature branch, Git may see it as deleted on main and modified on feature, producing a "modify/delete" conflict instead of a normal content conflict. ```bash # Accept the rename, apply the edit to the new filename: git rm file1.txt # Manually add the new content to file2.txt, then: git add file2.txt git commit -m "Resolve rename + edit conflict" ``` Developers who see "modify/delete" often assume something broke. Nothing broke. The file moved, and Git needs your help connecting the edit to the new location.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.