Arbeiten mit Branches

Git Merge-Konflikte

Versionskontrollsysteme werden verwendet, um Beiträge von mehreren verteilten Autoren (in der Regel Entwickler) zu verwalten. Manchmal kann es vorkommen, dass mehrere Entwickler versuchen, denselben Inhalt zu bearbeiten. Wenn Entwickler A Code bearbeiten möchte, an dem Entwickler B gerade arbeitet, kann es zu einem Konflikt kommen. Um das Auftreten von Konflikten zu vermeiden, arbeiten Entwickler in voneinander getrennten isolierten Branches. Mit dem Befehl git merge werden in erster Linie separate Branches kombiniert und eventuell bestehende Bearbeitungskonflikte behoben.

Grundlegendes zu Merge-Konflikten

Merging und Konflikte gehören bei der Arbeit mit Git einfach dazu. Konflikte in anderen Versionskontrolltools wie SVN können kostspielig und zeitaufwändig werden. Aber mit Git klappt das Merging ganz einfach, weil die Lösung selbst herausfindet, wie neue Änderungen automatisch integriert werden können.

Konflikte entstehen in der Regel dann, wenn zwei Personen dieselben Zeilen in einer Datei geändert haben oder ein Entwickler eine Datei löscht, während ein anderer Entwickler diese ändert. In diesen Fällen kann Git nicht automatisch entscheiden, welcher Vorgang richtig ist. Die Konflikte betreffen nur den Entwickler, der den Merge durchführt – der Rest des Teams bemerkt von dem Konflikt nichts. Git kennzeichnet die betreffende Datei als "in Konflikt stehend" und stoppt den Merge-Vorgang. Es ist dann Aufgabe des Entwicklers, den Konflikt zu lösen.

Arten von Merge-Konflikten

Bei einem Merge können an zwei separaten Stellen Konflikte entstehen: zu Beginn und während des Merge-Vorgangs. Im Folgenden sprechen wir darüber, wie jedes dieser Konfliktszenarien behandelt werden kann.

Git kann Merge nicht starten

Der Start eines Merge-Vorgangs schlägt fehl, wenn Git erkennt, dass Änderungen entweder im Arbeitsverzeichnis oder in der Staging-Umgebung des aktuellen Projekts vorgenommen wurden. Git führt den Merge nicht aus, weil diese ausstehenden Änderungen durch die Commits überschrieben werden könnten, die gemergt werden. Wenn dies geschieht, liegt das nicht an Konflikten mit anderen Entwicklern, sondern an Konflikten mit ausstehenden lokalen Änderungen. Der lokale Zustand muss mithilfe der Befehle git stash, git checkout, git commit oder git reset stabilisiert werden. Bei einem Merge-Fehler beim Start wird die folgende Fehlermeldung ausgegeben:

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)

Bei Git tritt während dem Merge-Vorgang ein Fehler auf

Ein Fehler WÄHREND eines Merge-Vorgangs weist auf einen Konflikt zwischen dem aktuellen lokalen Branch und dem Branch hin, der gerade gemergt wird. Dies wiederum bedeutet einen Konflikt mit dem Code eines anderen Entwicklers. Git wird alles versuchen, um die Dateien zu mergen, überlässt dir aber die Aufgabe, Probleme mit in Konflikt stehenden Dateien manuell zu beheben. Bei einem Fehler während des Merge-Vorgangs wird die folgende Fehlermeldung ausgegeben:

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

Erstellen eines Merge-Konflikts

Damit du mit Merge-Konflikten vertrauter wirst, wird im nächsten Abschnitt ein Konflikt simuliert, der später untersucht und gelöst werden soll. Für das Beispiel wird eine Unix-ähnliche Git-CLI (Command Line Interface) verwendet, über die diese Simulation ausgeführt wird.

$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[master (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt

Dieses Codebeispiel führt eine Reihe von Befehlen aus, mit denen Folgendes erreicht wird:

  • Du erstellst ein neues Verzeichnis namens git-merge-test, wechselst zu diesem Verzeichnis und initialisierst ein neues Git-Repository.
  • Du erstellst eine neue Textdatei namens merge.txt mit einigen Inhalten.
  • Du fügst die Datei merge.txt zum Repository hinzu und committest sie.

Jetzt ist ein neues Repository mit einem Master-Branch und einer Datei namens merge.txt mit Inhalten entstanden. Als Nächstes erstellen wir einen neuen Branch, der für einen in Konflikt stehenden Merge-Vorgang verwendet werden soll.

$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

Die nachstehende Befehlsreihenfolge bewirkt Folgendes:

  • Du erstellst einen neuen Branch namens new_branch_to_merge_later und checkst ihn aus.
  • Du überschreibst die Inhalte in merge.txt.
  • Du committest den neuen Inhalt.

Mit diesem neuen Branch new_branch_to_merge_later haben wir einen Commit erstellt, der die Inhalte von merge.txt überschreibt.

git checkout master
Switched to branch 'master'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[master 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)

Mithilfe dieser Befehlskette wird der Master-Branch ausgecheckt, Inhalt zur Datei merge.txt hinzugefügt und dieser dann committet. Mit diesem Schritt werden aus unserem Beispiel-Repository zwei neue Commits: einer im Master-Branch und einer im Branch namens new_branch_to_merge_later. An dieser Stelle lassen wir Git new_branch_to_merge_later mergen und beobachten, was passiert.

$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

BUMM 💥. Es ist ein Konflikt aufgetreten. Danke für den Hinweis, Git!

Identifizierung von Merge-Konflikten

Wie wir aus dem vorangehenden Beispiel gelernt haben, erstellt Git einen beschreibenden Text, der uns über das Auftreten eines KONFLIKTS informiert. Detailliertere Informationen dazu erhalten wir durch die Ausführung des Befehls git status.

$ 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:   merge.txt

Der Output aus git status weist darauf hin, dass der Konflikt zu nicht gemergten Pfaden geführt hat. Die Datei merge.text wird jetzt im Status "modifiziert" angezeigt. Sehen wir uns die Datei an, um herauszufinden, was geändert wurde.

$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later

Hier haben wir den Befehl cat verwendet, um die Inhalte der Datei merge.txt hervorzuheben, und können feststellen, dass seltsame neue Ergänzungen gemacht wurden.

  • <<<<<<< HEAD
  • =======
  • >>>>>>> new_branch_to_merge_later

Betrachte diese neue Zeilen als "problematische Trennlinien". Die Zeile ======= ist das "Zentrum" des Konflikts. Alle Inhalte zwischen der Mitte und der Zeile <<<<<<< HEAD sind Inhalte, die im aktuellen Master-Branch vorhanden sind, auf den die HEAD-Referenz verweist. Hingegen sind alle Inhalte zwischen der Mitte und >>>>>>> new_branch_to_merge_later Inhalt, der in unserem zu mergenden Branch vorliegt.

Behebung von Merge-Konflikten mithilfe der Befehlszeile

Der direkteste Weg, um Merge-Konflikte zu beheben, ist die Bearbeitung der in Konflikt stehenden Datei. Öffne hierzu die Datei merge.txt im Editor deiner Wahl. Bei unserem Beispiel hier entfernen wir einfach alle problematischen Trennlinien. Der geänderte Inhalt in merge.txt sollte wie folgt aussehen:

this is some content to mess with
content to append
totally different content to merge later

Sobald du die Datei bearbeitet hast, kannst du mit git add merge.txt den neu gemergten Inhalt stagen. Zum Abschluss des Merge-Vorgangs erstellst du einen neuen Commit, indem du folgenden Befehl ausführst:

git commit -m "merged and resolved the conflict in merge.txt"

Git erkennt, dass der Konflikt behoben wurde, und erstellt einen neuen Merge-Commit, um den Vorgang abzuschließen.

Git-Befehle für die Behebung von Merge-Konflikten

Allgemeine Tools

git status

Der status-Befehl wird für die Arbeit mit Git häufig verwendet und während eines Merge-Vorgangs können damit in Konflikt stehende Dateien identifiziert werden.

git log --merge

Durch die Übergabe des Arguments --merge an den git log-Befehl wird ein Protokoll mit einer Liste an Commits erstellt, die zwischen mergenden Branches für Konflikte sorgen.

git diff

Mithilfe von diff lassen sich Unterschiede zwischen Zuständen von Repositorys/Dateien einfacher auffinden, was für die Prognose und Vermeidung von Merge-Konflikten nützlich ist.

Tools für den Fall, wenn Git keinen Merge-Vorgang starten kann

git checkout

Der Befehl checkout kann verwendet werden, um Änderungen in Dateien rückgängig zu machen oder um Branches zu wechseln.

git reset --mixed

reset wird genutzt, um Änderungen am Arbeitsverzeichnis und am Staging-Bereich zu widerrufen.

Tools für den Fall, wenn während eines Merge-Vorgangs Git-Konflikte entstehen

git merge --abort

Durch die Ausführung des Befehls git merge mit der Option --abort kannst du den Merge-Prozess verlassen und den Branch auf den Zustand vor dem Merge zurücksetzen.

git reset

Git reset kann während eines Merge-Konflikts verwendet werden, um in Konflikt stehende Dateien auf einen als funktionierend bekannten Zustand zurückzusetzen.

Zusammenfassung

Merge-Konflikte können eine ziemliche Wirkung haben. Zum Glück bietet Git leistungsstarke Tools, um Konflikten aus dem Weg zu gehen oder sie zu lösen. Git kann die meisten Merge-Vorgänge dank automatischer Merging-Features selbst handhaben. Ein Konflikt entsteht, wenn in zwei separaten Branches Bearbeitungen derselben Zeile in einer Datei vorgenommen wurden oder wenn eine Datei in einem Branch gelöscht, aber in einem anderen bearbeitet wurde. Konflikte entstehen am häufigsten bei der Arbeit in einer Teamumgebung.

Es gibt zahlreiche Tools, um Merge-Konflikte zu beheben. Git hat genügend Befehlszeilentools, die hier besprochen wurden. Weitere detaillierte Informationen zu diesen Tools findest du auf den jeweiligen Seiten zu git log, git reset, git status, git checkout und git reset. Neben Git bieten viele Tools von Drittanbietern optimierte Support-Features für Merge-Konflikte an.

Möchtest du Branching ausprobieren?

Sieh dir dieses interaktive Tutorial an.

Jetzt loslegen