Wie man mit Merge-Konflikten in Git umgeht

Avatar of Tobias Günther
Tobias Günther am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Jeder hat eine Liste von Dingen, die er nicht mag: einen Arzttermin beim Zahnarzt, einen Stau oder einen Flugausfall. Als ich mein Buch vorbereitete, war ich nicht überrascht, dass viele Designer und Entwickler ohne zu zögern Merge-Konflikte auf diese Liste setzen würden.

Wenn Sie Git zur Versionskontrolle verwenden, gibt es nichts zu befürchten. Sobald Sie verstehen, wie Merge-Konflikte funktionieren und wie man mit ihnen umgeht, bin ich sicher, dass Sie sie von dieser Liste streichen können.

Sie können nichts kaputt machen

Das Erste, was Sie bedenken sollten, ist, dass Sie einen Merge jederzeit rückgängig machen und zum Zustand vor dem Auftreten des Konflikts zurückkehren können. Sie können jederzeit rückgängig machen und neu beginnen.

Wenn Sie von einem anderen Versionskontrollsystem (z. B. Subversion) kommen, sind Sie vielleicht traumatisiert: Konflikte in Subversion haben den (wohlverdienten) Ruf, unglaublich komplex und unangenehm zu sein. Ein Grund dafür ist, dass Git in dieser Hinsicht einfach anders funktioniert als Subversion. Als Konsequenz kann Git die meisten Dinge während eines Merges selbst erledigen – und Ihnen vergleichsweise einfache Szenarien zur Lösung überlassen.

Außerdem beeinträchtigt ein Konflikt immer nur Sie selbst. Er bringt Ihr gesamtes Team nicht zum Stillstand und beeinträchtigt auch nicht Ihr zentrales Repository. Das liegt daran, dass in Git Konflikte nur auf Ihrem lokalen Rechner auftreten können – und nicht auf dem Server.

Wie ein Merge-Konflikt auftritt

In Git ist "Merging" der Vorgang, einen anderen Branch in Ihren aktuellen Arbeitsbranch zu integrieren. Sie übernehmen Änderungen aus einem anderen Kontext (das ist im Wesentlichen ein Branch: ein Kontext) und kombinieren sie mit Ihren aktuellen Arbeitsdateien. Wenn Sie mit dem Konzept im Allgemeinen neu sind, werfen Sie einen Blick auf diese Einführung in Branching.

Eine großartige Sache daran, Git als Ihr Versionskontrollsystem zu haben, ist, dass es das Mergen extrem einfach macht: In den meisten Fällen findet Git heraus, wie neue Änderungen integriert werden.

Es gibt jedoch eine Handvoll Situationen, in denen Sie eingreifen und Git mitteilen müssen, was zu tun ist. Am häufigsten tritt dies auf, wenn Änderungen an derselben Datei in beiden Branches vorgenommen wurden. Selbst in diesem Fall wird Git dies wahrscheinlich selbst herausfinden. Aber wenn zwei Personen dieselben Zeilen in dieser Datei geändert haben oder wenn eine Person beschlossen hat, sie zu löschen, während die andere Person beschlossen hat, sie zu ändern, kann Git einfach nicht wissen, was richtig ist. Git markiert die Datei dann als mit einem Konflikt versehen – den Sie lösen müssen, bevor Sie Ihre Arbeit fortsetzen können.

Wie man einen Merge-Konflikt löst

Wenn Sie mit einem Merge-Konflikt konfrontiert werden, ist der erste Schritt zu verstehen, was passiert ist. Hat ein Kollege die gleiche Datei auf denselben Zeilen wie Sie bearbeitet? Haben sie eine Datei gelöscht, die Sie geändert haben? Haben Sie beide eine Datei mit demselben Namen hinzugefügt?

Git teilt Ihnen über "git status" mit, dass Sie "unmerged paths" haben (was nur eine andere Art ist, Ihnen mitzuteilen, dass Sie einen oder mehrere Konflikte haben).

Konflikt-Markup

Werfen wir einen detaillierten Blick darauf, wie der häufigste Fall gelöst wird: Wenn zwei Änderungen dieselbe Datei auf denselben Zeilen beeinflusst haben.

Jetzt ist es an der Zeit, sich den Inhalt der konflikthaltigen Datei anzusehen. Öffnen Sie sie buchstäblich in Ihrem Code-Editor. Git ist nett genug, den problematischen Bereich in der Datei zu markieren, indem er ihn mit "<<<<<<< HEAD" und ">>>>>>> [anderer/branch/name]" umschließt.

Der Code aus Ihrem aktuellen Branch steht oben, der Code aus dem Branch, den Sie mergen, steht unten.

Der Inhalt nach dem ersten Marker stammt aus Ihrem aktuellen Arbeitsbranch. Nach den spitzen Klammern teilt uns Git mit, woher (von welchem Branch) die Änderungen stammen. Eine Zeile mit "=======" trennt die beiden konfligierenden Änderungen.

Aufräumen

Unsere Aufgabe ist es nun, diese Zeilen aufzuräumen: Wenn wir fertig sind, sollte die Datei genau so aussehen, wie wir sie haben wollen. Es kann notwendig sein, sich mit dem Teamkollegen zu beraten, der die konflikthaltigen Änderungen vorgenommen hat, um zu entscheiden, welcher Code endgültig richtig ist. Vielleicht ist es Ihrer, vielleicht ist es ihrer, oder vielleicht eine Mischung aus beidem.

Die Rohdatei in Ihrem Editor zu öffnen und sie dort aufzuräumen, ist durchaus legitim, aber nicht sehr komfortabel. Die Verwendung eines speziellen Merge-Tools kann diese Aufgabe erheblich erleichtern. Sie können Ihr bevorzugtes Tool mit dem Befehl "git config" konfigurieren. Konsultieren Sie die Dokumentation Ihres Tools für detaillierte Anweisungen. Beachten Sie, dass nur weil Sie Git installiert haben, dies nicht bedeutet, dass Sie ein spezielles Merge-Tool installiert haben. Dies sind separate, optionale Software-Tools.

Dann können Sie im Falle eines Konflikts später einfach "git mergetool" eingeben.

Für dieses Beispiel habe ich Kaleidoscope auf Mac verwendet

Die linken und rechten Spalten stehen für die konfligierenden Änderungen; eine weitaus elegantere Visualisierung als "<<<<<<<" und ">>>>>>>".

Sie können nun einfach umschalten, welche Änderung übernommen werden soll. Die mittlere Spalte zeigt den resultierenden Code; bei guten Tools können Sie diesen sogar weiter bearbeiten.

Nachdem Sie die Datei mit dem endgültigen Code bereinigt haben, müssen Sie sie nur noch speichern. Um Git einen Hinweis zu geben, dass Sie mit dieser Datei fertig sind, sollten Sie das Merge-Tool beenden, um fortzufahren. Hinter den Kulissen wird dadurch Git angewiesen, einen "git add"-Befehl für die (nun ehemalige) konflikthaltige Datei auszuführen. Dies markiert den Konflikt als gelöst. Sollten Sie sich entscheiden, kein Merge-Tool zu verwenden und die Datei stattdessen in Ihrem Editor zu bereinigen, müssen Sie die Datei manuell als gelöst markieren (indem Sie "git add <dateiname>" ausführen).

Schließlich muss nach der Behebung aller Konflikte eine Merge-Konfliktsituation mit einem regulären Commit abgeschlossen werden.

Wie man einen Merge rückgängig macht

Wie bereits erwähnt, können Sie jederzeit zum Zustand vor dem Beginn des Merges zurückkehren. Das sollte Ihnen die Zuversicht geben, dass Sie nichts kaputt machen können. Auf der Kommandozeile erledigt ein einfaches "git merge --abort" dies für Sie.

Wenn Sie einen Fehler beim Auflösen eines Konflikts gemacht haben und dies erst nach Abschluss des Merges feststellen, können Sie ihn immer noch leicht rückgängig machen: Setzen Sie den Commit einfach mit "git reset --hard <commit-hash>" auf den Zustand vor dem Merge zurück und beginnen Sie erneut.

Werkzeuge können die Dinge erleichtern

Ich habe es bereits kurz erwähnt: Mit guten Werkzeugen auszustatten, kann Ihr Leben erheblich erleichtern. Ein richtiges Merge-Tool hilft Ihnen, ein Konfliktszenario besser zu verstehen und die richtige Entscheidung zu treffen.

Seien Sie zuversichtlich

Mit all den Sicherheitsnetzen, die Git bietet, gibt es wirklich keinen Grund, Angst vor Merge-Konflikten zu haben. Sobald Sie verstanden haben, wie sie funktionieren und welche Optionen Sie haben, sollten Sie bereit sein, zu mergen, als gäbe es kein Morgen. Denken Sie immer daran: Sie können nichts kaputt machen!

Anmerkung des Herausgebers

Tobias hat Tower bescheiden als ausgezeichnetes Werkzeug zur Unterstützung bei Merge-Konflikten ausgelassen. Tatsächlich ist einer der Gründe, warum ich persönlich Tower benutze, dass es mir bei Merge-Konflikten hilft.

Es ist sehr klar, wenn Sie einen Konflikt haben


Und durch Rechtsklick auf die konflikthaltige Datei erhalten Sie einige schöne Optionen

Mein üblicher Prozess ist also

  1. Ist es für mich sehr offensichtlich, ob meine Änderungen an dieser Datei oder die Änderungen des anderen Branches an dieser Datei „gewinnen“ sollen? Wenn ja, wählen Sie die entsprechende Option "Resolve <file> Using Mine" oder "Resolve <file> Using Theirs".
  2. Wenn ich genauer hinschauen muss, öffne ich sie in einem Code-Editor und schaue sie mir an. Dann kann ich vielleicht immer noch eine dieser Optionen verwenden.
  3. Wenn es komplizierter ist, behebe ich es manuell und wähle dann aus Tower "Mark <file> as Manually Resolved".
  4. Manchmal verwende ich ein Merge-Tool, wenn es viele komplexe Korrekturen gibt, was Tower ebenfalls über die Option "Open <file> in Merge Tool" unterstützt.