✦ Oplossingen · Server- en developerfouten

CONFLICT (content): Merge conflict in … – zo los je het op

Git meldt ‘CONFLICT (content): Merge conflict in …’ en ‘Automatic merge failed’? Lees wat de conflictmarkeringen betekenen en hoe je het stap voor stap oplost.

Zo ziet de foutmelding eruit

  • CONFLICT (content): Merge conflict in index.php
  • Automatic merge failed; fix conflicts and then commit the result.
  • You have unmerged paths.
  • both modified: index.php
  • error: could not apply 1a2b3c4... commitbericht
  • Pulling is not possible because you have unmerged files.

Waarom gebeurt dit?

Een merge conflict ontstaat als Git twee lijnen van werk moet samenvoegen en op dezelfde plek in een bestand twee verschillende wijzigingen tegenkomt. Git voegt veranderingen in verschillende regels of bestanden zelf samen. Maar hebben jij en een collega (of jij op twee branches) dezelfde regels anders aangepast, dan weet Git niet welke versie goed is. Het stopt dan halverwege met CONFLICT (content): Merge conflict in … en Automatic merge failed; fix conflicts and then commit the result.

Dat gebeurt bij git merge, maar ook bij git pull (dat is een fetch plus een merge of rebase), git rebase, git cherry-pick en git stash pop. Je repository staat dan in een tussentoestand: de bestanden zonder conflict zijn al samengevoegd, de bestanden met conflict bevatten conflictmarkeringen en wachten op jouw keuze. Er is niets kapot en er is niets verloren; Git wacht alleen op jou.

Er zijn ook varianten zonder regels-conflict: CONFLICT (modify/delete) als de ene kant een bestand wijzigde en de andere het verwijderde, en CONFLICT (rename/delete) of CONFLICT (add/add) bij hernoemde of op twee plekken nieuw aangemaakte bestanden. Die los je op dezelfde manier op, alleen kies je dan of het bestand blijft bestaan.

Zo herken je dit probleem

  • Git noemt letterlijk CONFLICT en de bestandsnaam, en git status toont ‘You have unmerged paths’ met both modified.
  • In het bestand staan blokken met <<<<<<<, ======= en >>>>>>>. Staan die markeringen al live op je website, dan is een conflict per ongeluk meegecommit.
  • Weigert Git te pushen met ‘rejected’ en ‘non-fast-forward’, dan is er (nog) geen conflict maar loop je achter: zie push rejected (non-fast-forward).
  • Meldt Git bij een rebase dat je in ‘detached HEAD’ zit, dan is dat normaal tijdens een rebase; lees detached HEAD alleen als je na de rebase nog zo staat.

Zo los je het op, stap voor stap

Menunamen kunnen per versie of toestel iets anders heten. Loop de stappen op volgorde af en stop zodra het werkt.

  1. Kijk welke bestanden in conflict zijn

    Begin met git status. Onder ‘Unmerged paths’ zie je per bestand wat er speelt, meestal both modified. Bovenaan staat ook of je midden in een merge of een rebase zit; dat bepaalt straks hoe je afrondt. Werk de lijst bestand voor bestand af.

    git status
    git diff --name-only --diff-filter=U
  2. Begrijp de conflictmarkeringen

    Open het bestand. Tussen <<<<<<< HEAD en ======= staat jouw huidige versie, tussen ======= en >>>>>>> branchnaam de versie die binnenkomt. Kies de ene, de andere, of combineer ze tot de juiste code, en haal alle drie de markeringsregels weg. De meeste editors, zoals VS Code, tonen knoppen om een kant te accepteren.

    <<<<<<< HEAD
    $prijs = 95;
    =======
    $prijs = 99;
    >>>>>>> feature/nieuwe-prijzen
  3. Markeer het bestand als opgelost

    Ben je klaar met een bestand, controleer dan dat er geen markeringen meer in staan en dat de code nog werkt (draai je tests of open de pagina lokaal). Daarna vertel je Git met git add dat dit bestand is opgelost. Bij een verwijderd bestand gebruik je git rm als het weg moet.

    grep -n '^<<<<<<<\|^>>>>>>>\|^=======$' index.php
    git add index.php
  4. Rond de merge af

    Zijn alle bestanden opgelost, dan maak je de merge-commit. Git vult zelf een commitbericht voor; dat mag je laten staan. Daarna kun je normaal pushen.

    git commit
    git push
  5. Bij een rebase: ga verder met --continue

    Gaf git rebase of git pull --rebase het conflict, dan rond je niet af met een commit maar met git rebase --continue. Git past daarna de volgende commit toe, en dat kan opnieuw een conflict geven; herhaal dan stap 2 en 3. Wil je één commit overslaan, gebruik git rebase --skip, maar alleen als je zeker weet dat die commit niet nodig is.

    git add index.php
    git rebase --continue
  6. Kies in één keer een hele kant

    Wil je voor een bestand gewoon de ene versie houden, dan kan dat met git checkout --ours of --theirs. Let op: bij een merge is ours je eigen branch en theirs de branch die je binnenhaalt. Bij een rebase is het omgekeerd: daar is ours de branch waar je bovenop zet en theirs je eigen commit. Recente Git-versies kennen ook git restore --ours.

    git checkout --ours config.php
    git checkout --theirs package-lock.json
    git add config.php package-lock.json
  7. Twijfel je? Breek af en begin opnieuw

    Weet je niet meer wat je aan het doen bent, dan kun je de hele merge of rebase terugdraaien naar de toestand van daarvoor. Je werk van vóór de merge blijft dan bewaard. Lukt het daarna opnieuw niet, haal dan eerst de wijzigingen van de ander op en bekijk ze met git log en git diff voordat je weer samenvoegt.

    git merge --abort
    git rebase --abort
    git cherry-pick --abort
  8. Voorkom grote conflicten

    Haal regelmatig de laatste versie op, houd branches kort en klein, en commit gegenereerde bestanden (zoals gebouwde CSS of JavaScript) liever niet. Bij package-lock.json los je een conflict het makkelijkst op door één kant te kiezen en daarna npm install te draaien, zodat het lockbestand opnieuw klopt met package.json.

    git fetch origin
    git rebase origin/main
    npm install

Let op: Push nooit een bestand waar nog conflictmarkeringen in staan. In PHP of JavaScript geeft dat direct een syntaxfout, en op een live website kan dat een witte pagina of een 500-fout opleveren.

Merge of rebase: wat is het verschil bij conflicten?

Bij een merge voegt Git twee branches samen in één nieuwe merge-commit. Je lost alle conflicten in één keer op en rondt af met git commit.

Bij een rebase zet Git jouw commits één voor één opnieuw bovenop de andere branch. Een conflict kan daardoor per commit terugkomen, en je rondt elke stap af met git rebase --continue.

  • Afbreken: git merge --abort of git rebase --abort.
  • ours/theirs: bij merge is ‘ours’ jouw branch, bij rebase de doelbranch.
  • Een rebase herschrijft je commits. Doe dat niet met commits die anderen al hebben opgehaald.

Wanneer schakel je hulp in?

  • Het conflict zit in code die je niet zelf hebt geschreven en je weet niet welke versie de juiste is.
  • Er staan conflictmarkeringen op je live website en je wilt snel en veilig terug naar een werkende versie.
  • Een rebase loopt steeds opnieuw vast op dezelfde bestanden en je durft niet verder.
  • Je hebt in paniek een reset of force-push gedaan en mist nu werk; vaak is dat via git reflog nog terug te halen.

Lukt het niet? Wij helpen

Kom je er met deze stappen niet uit, of wil je het liever niet zelf doen? We kijken online mee of komen langs. Hulp op afstand kost €20 per uur; komen we langs, dan is de prijs op aanvraag. Je weet vooraf waar je aan toe bent.

Aanvraag

Hulp aanvragen

Schrijf kort wat er misgaat en wat je al hebt geprobeerd. Kies of we bellen, online meekijken of langskomen.

Veelgestelde vragen

Vragen over dit probleem

Ben ik mijn werk kwijt bij een merge conflict?

Nee. Je eigen versie en die van de ander staan allebei nog in het bestand of in de geschiedenis. Met git merge --abort ga je terug naar de toestand van vóór de merge.

Wat betekent ‘Automatic merge failed; fix conflicts and then commit the result’?

Git heeft wat het zelf kon samenvoegen al gedaan, maar heeft op een of meer plekken jouw keuze nodig. Los de conflicten op, doe git add en daarna git commit.

Wat is het verschil tussen --ours en --theirs?

Bij een merge is ‘ours’ de branch waarop je staat en ‘theirs’ de branch die je binnenhaalt. Bij een rebase is dat precies andersom.

Kan ik een conflict voorkomen?

Niet altijd, maar wel kleiner maken: haal vaak de laatste versie op, houd branches kort en werk niet met meerdere mensen tegelijk in dezelfde regels.