Merge-Konflikte
Ursachen von Git-Merge-Konflikten, Konfliktmarkierungen lesen und Schritt-für-Schritt-Anleitung zum Lösen, Abbrechen oder Vermeiden.
Ein Merge-Konflikt entsteht, wenn Git zwei Änderungssätze nicht automatisch zusammenführen kann. Dies geschieht, wenn zwei Branches dieselben Zeilen derselben Datei auf unterschiedliche Weise ändern oder wenn ein Branch eine Datei löscht, die ein anderer Branch bearbeitet hat. Da Git nicht wissen kann, welche Version korrekt ist, hält es den Merge an und überlässt die Entscheidung Ihnen.
Diese Seite erklärt, warum Konflikte entstehen, wie man einen Konflikt reproduziert, wie man die von Git in die Dateien eingefügten Markierungen liest und auf welche verschiedenen Weisen man einen Konflikt lösen, abbrechen oder sogar verhindern kann. Der Befehl git merge verbindet zwei Branches und ist der Ort, an dem die meisten Konflikte auftreten.
Git verwaltet das Zusammenführen besser als die meisten Versionskontrollsysteme und integriert Änderungen automatisch, wenn die beiden Seiten unterschiedliche Teile einer Datei berühren. Ein Konflikt ist daher kein Fehler in Ihrem Workflow — er ist Gits Aufforderung an einen Menschen, eine Entscheidung zu treffen. Wenn Git keine Entscheidung treffen kann, markiert es die Datei als konfliktbehaftet und stoppt den Merge, damit nichts verloren geht.

Wann entstehen Konflikte?
Nicht jeder Merge erzeugt einen Konflikt. Zu wissen, wann einer wahrscheinlich ist, hilft Überraschungen zu vermeiden:
- Dieselben Zeilen auf beiden Seiten bearbeitet — der klassische Fall. Zwei Branches ändern dieselbe Zeile in
example.txtauf unterschiedliche Weise. - Eine Datei auf einem Branch bearbeitet, auf dem anderen gelöscht — Git kann nicht entscheiden, ob es die Änderungen beibehalten oder die Löschung berücksichtigen soll.
- Unterschiede bei Leerzeichen, Zeilenenden oder Kodierung — Änderungen, die identisch aussehen, können dennoch kollidieren, wenn die Bytes unterschiedlich sind.
Wenn die beiden Branches unterschiedliche Zeilen oder unterschiedliche Dateien berühren, führt Git sie automatisch ohne Konflikt zusammen.
Häufige Merge-Unterbrechungen
Git kann einen Merge an zwei verschiedenen Punkten stoppen, und die beiden Fälle erfordern unterschiedliche Lösungen. Es hilft zu wissen, welchen Fall man vor sich hat.
Merge-Fehler beim Start
Git verweigert den Start eines Merges, wenn nicht committete Änderungen im Arbeitsverzeichnis oder Staging-Bereich durch die eingehenden Commits überschrieben würden. Dies ist kein inhaltlicher Konflikt — es ist Git, das noch nicht committete Arbeit schützt. Um die Kontrolle über Ihren lokalen Zustand zurückzugewinnen, verwenden Sie git stash (Änderungen zwischenspeichern), git commit (speichern), git checkout oder git reset (verwerfen), und führen Sie dann den Merge erneut aus. Die Meldung sieht so aus:
error: Your local changes to the following files would be overwritten by merge:
example.txt
Please commit your changes or stash them before you merge.
AbortingFehler während des Merges
Ein Fehler während des Merges bedeutet, dass Git begonnen hat, die Branches zusammenzuführen, aber auf einen echten inhaltlichen Konflikt zwischen Ihrem aktuellen Branch und dem zusammenzuführenden Branch gestoßen ist. Der Merge bleibt halb abgeschlossen, damit Sie ihn lösen können. Die Meldung sieht so aus:
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.Einen Merge-Konflikt erzeugen
Sie können einen Konflikt in einem Wegwerf-Repository reproduzieren, um das Lösen gefahrlos zu üben. Beginnen Sie damit, ein Repository mit einer einzigen committeten Datei zu erstellen:
mkdir test-dir
cd test-dir
git init .
echo "some content" > example.txt
git add example.txt
git commit -m "initial commit"
[master (root-commit) a45c22d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 example.txtDies erstellt ein Verzeichnis namens test-dir, initialisiert ein Repository und committet example.txt mit der Zeile some content. Wir haben jetzt einen Branch (master) und eine Datei. Als nächstes erstellen Sie einen zweiten Branch und ändern dieselbe Zeile — das macht den Konflikt möglich:
git checkout -b branch_to_merge
echo "completely different content to merge later" > example.txt
git commit -m "edit the content of example.txt to make a conflict"
[branch_to_merge 4221135] edit the content of example.txt to make a conflict
1 file changed, 1 insertion(+), 1 deletion(-)git checkout -b branch_to_merge erstellt den Branch und wechselt zu ihm. Wir überschreiben example.txt und committen die Änderung, sodass dieser Branch nun eine andere Version dieser Zeile hat. Wechseln Sie zurück zu master und ändern Sie dieselbe Datei auf eine andere Weise:
git checkout master
Switched to branch 'master'
echo "content to add" >> example.txt
git commit -m "added content to example.txt"
[master 11ab34b] added content to example.txt
1 file changed, 1 insertion(+)Jetzt haben beide Branches ihren eigenen Commit, der example.txt berührt. Führen Sie den Merge aus, und Git meldet den Konflikt, den es nicht selbst lösen kann:
git merge branch_to_merge
Auto-merging example.txt
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.Merge-Konflikte identifizieren
Neben der vom Merge ausgegebenen Meldung zeigt Ihnen git status genau, welche Dateien konfliktbehaftet sind, indem es sie unter Unmerged paths auflistet:
git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: example.txtboth modified bedeutet, dass die Datei auf beiden Seiten geändert wurde. Öffnen Sie die Datei oder verwenden Sie cat, um die von Git eingefügten Konfliktmarkierungen zu sehen:
cat example.txt
<<<<<<< HEAD
some content
content to add
=======
completely different content to merge later
>>>>>>> branch_to_mergeLesen Sie die drei Markierungen so:
<<<<<<< HEAD— Beginn des Konflikts. Alles darunter bis zu=======gehört zu Ihrem aktuellen Branch (master, auf denHEADzeigt).=======— die Trennlinie zwischen den beiden Versionen.>>>>>>> branch_to_merge— Ende des Konflikts. Die Zeilen zwischen=======und dieser Markierung stammen aus dem Branch, den Sie zusammenführen.
Um den gesamten Merge zu verwerfen und zum genauen Zustand vor dem Start zurückzukehren, führen Sie git merge --abort aus. Weitere Informationen zu den Markierungen finden Sie auf der Seite git merge.
Merge-Konflikte lösen
Manuelles Lösen
Öffnen Sie die konfliktbehaftete Datei in Ihrem Editor, entscheiden Sie, wie der endgültige Inhalt aussehen soll, und löschen Sie alle drei Markierungen (<<<<<<<, =======, >>>>>>>). Sie können eine Seite, die andere oder eine manuell zusammengeführte Kombination beider behalten. Wenn Sie zum Beispiel beide Inhaltsteile behalten, ergibt das:
some content
content to add
completely different content to merge laterSobald die Markierungen entfernt und der Inhalt korrekt ist, stagen Sie die Datei mit git add und committen Sie, um den Merge abzuschließen:
git add example.txt
git commit -m "resolve merge conflict in example.txt"Das Ausführen von git commit nach einem Konflikt erstellt einen Merge-Commit, der beide Branch-Historien miteinander verbindet.
Lösen durch Auswahl einer Seite
Wenn Sie einfach die Version einer Datei eines Branches vollständig behalten möchten, müssen Sie nicht manuell bearbeiten. Checken Sie die gewünschte Seite aus, stagen und committen Sie dann:
git checkout --ours example.txt # keep the version from the current branch (master)
git checkout --theirs example.txt # keep the version from the incoming branch
git add example.txt--ours behält den Inhalt Ihres aktuellen Branches; --theirs behält den Inhalt des eingehenden Branches.
Lösen mit einem visuellen Werkzeug
Bei größeren Konflikten öffnet git mergetool ein konfiguriertes nebeneinander angezeigtes Diff-Werkzeug, mit dem Sie Konflikte interaktiv lösen können, anstatt Markierungen manuell zu bearbeiten. Führen Sie git mergetool aus, um alle konfliktbehafteten Dateien durchzugehen, oder git mergetool example.txt für eine bestimmte Datei.
Einen Merge abbrechen
Wenn Sie entscheiden, dass der Merge ein Fehler war, oder lieber mit einem sauberen Arbeitsverzeichnis neu beginnen möchten, brechen Sie ihn ab:
git merge --abortDadurch werden Ihr Branch und Ihr Arbeitsverzeichnis in den genauen Zustand wiederhergestellt, in dem sie sich vor dem Ausführen von git merge befanden — keine Markierungen, keine halb zusammengeführten Dateien. Verwenden Sie dies, wenn der Konflikt mehr ist, als Sie gerade bewältigen möchten.
Merge-Konflikte verhindern
Konflikte sind normal, aber Sie können reduzieren, wie oft und wie stark sie Sie treffen:
- Oft mit dem Hauptbranch mergen oder rebasen, damit Ihr Branch nie zu weit von ihm abweicht.
- Commits klein und fokussiert halten und umfangreiche Neuformatierungen nicht im selben Commit wie logische Änderungen vornehmen.
- Kommunizieren, damit nicht zwei Personen gleichzeitig dieselbe Datei umschreiben.
- Die Überschneidung mit git diff vorab prüfen, bevor Sie mergen, um zu sehen, welche Zeilen kollidieren könnten.
Befehlsübersicht
Dies sind die Befehle, die Sie am häufigsten beim Umgang mit Konflikten verwenden:
| Werkzeug | Beschreibung |
|---|---|
git status | Hilft dabei, konfliktbehaftete Dateien zu finden. |
git mergetool | Öffnet ein visuelles Diff-Werkzeug zum interaktiven Lösen von Konflikten. |
git diff | Zeigt Unterschiede zwischen Commits, Branches oder Dateien, um potenzielle Konflikte vor dem Mergen zu erkennen. |
git checkout --ours/--theirs | Ersetzt die konfliktbehaftete Datei durch den Inhalt des aktuellen oder eingehenden Branches. |
git reset --mixed | Hebt das Staging von Dateien auf, lässt das Arbeitsverzeichnis jedoch unverändert. |
git merge --abort | Bricht den aktuellen Merge ab und stellt das Arbeitsverzeichnis in den Zustand vor dem Merge wieder her. |
git reset | Setzt den Index auf HEAD zurück und hilft dabei, konfliktbehaftete Dateien aus dem Staging zu entfernen. |