2.3 Git Branches
Inhalt
Im vorherigen Kapitel haben wir gelernt, dass man nur dann seine Änderungen pushen kann, wenn einem niemand anders zuvorkam. Um diesem Problem aus dem Weg zu gehen, kann ein Branch (engl. für Ast/Zweig) verwendet werden, welcher zu einem späteren Zeitpunkt wieder auf den Hauptpfad gemerged wird.
Im ersten Kapitel haben wir gelernt, dass Git mit jedem Commit ein Snapshot der Daten und eine Referenz auf den vorgehenden Commit speichert. Ein Branch ist nichts anderes als ein Zeiger auf einen spezifischen Snapshot.
Erzeugen wir mit git branch testing
einen neuen Branch namens “testing”, so wird ein Zeiger erstellt, welcher auf den selben Commit zeigt auf dem man sich im Moment befindet. Damit Git weiss, wo man sich im Moment gerade befindet, gibt es einen speziellen Zeiger namens HEAD
:
|
|
Wie man auf der Skizze erkennen kann, wurde der neue Branch “testing” erstellt. Wir befinden uns aber immer noch auf dem “master” Branch (HEAD). Um nun auf den neuen Branch zu wechseln, können wir den Befehl git checkout testing
verwenden.
Protipp: Um einen neuen Branch zu erstellen und gleich auf diesen zu wechseln, kann der Befehl git checkout -b <branchname>
verwendet werden.
Erstellen wir nun einen Commit auf dem “testing” Branch, wechseln wieder zurück auf den Master und erstellen auch dort einen Commit, dann zeigt sich folgendes Bild:
|
|
Oder anders dargestellt:
|
|
Beispiel für Branching und Merging
Stell dir vor du bist TV, du hast bereits alle Mails und Alerts abgearbeitet, niemand will etwas von dir und du hast Zeit endlich an der Story zu arbeiten, welche du in diesem Sprint übernommen hast. Du wechselst also ins Ansible Repo und erstellst einen neuen Branch:
|
|
Wie du so am YAML-Programmieren bist wie ein grosser, kommt plötzlich ein Ticket rein. Auf einem Grafana-Dashboard muss etwas angepasst werden und zwar pronto. Um die Änderungen an deiner Story zu speichern, commitest du diese. Anschliessend wechselst du auf den Master Branch (damit du vom aktuellen produktiven Stand aus Arbeiten kannst). Wie immer pullst du die letzten Änderungen und erstellst dann einen weiteren Branch um das Dashboard zu flicken:
|
|
Zwischenbemerkung: in unserem Fall würdest du nun deine Änderungen pushen, einen Mergerequest erstellen und jemand für die Peerreview suchen und anschliessend im Gitlab mergen (Siehe dazu mehr im Kapitel Gitlab ). Da wir in diesem Kapitel jedoch Git im generellen anschauen wollen, wird hier dieser Workflow beschrieben.
An diesem Punkt kannst du auf dem “bugfix” Branch noch Tests ausführen und evtl. in einem weiteren Commit noch nachbessern. Gehen wir aber davon aus, dass alles in Ordnung ist und die Änderungen in den “master” soll. Also zurück auf den Masterbranch wechseln und die Änderungen vom “bugfix” Branch mergen:
|
|
Skizziert sieht das so aus:
|
|
Da der Commit 4 direkt nach dem Commit 2 in der Abfolge kommt, konnte der Master-Pointer einfach ein Commit nach vorne verschoben werden (Siehe “Fast-forward” im Command output)
Da nun alle wieder zufrieden sind, die Infrastruktur immer noch ruhig und du wieder Zeit hast an der Story weiterzuarbeiten machst du folgende Schritte:
|
|
Somit ergibt sich folgendes Bild:
|
|
Da nun der Masterbranch weiter ist als der Punkt, wo wir mit unserem Storybranch abzweigten, kann der Pointer bei einem Merge nicht einfach nach vorne gerückt werden wie vorher. Stattdessen macht Git einen Drei-Wege-Merge. Git verwendet die Branch-Spitzen (also Commit 5 und Commit 4) sowie den letzten gemeinsamen Vorfahren (Commit 2) und erstellt daraus einen neuen Snapshot/Commit:
|
|
|
|
Einfache Mergekonflikte
Im oben erwähnten Beispiel ist alles automatisch gegangen beim Mergen. Es gibt jedoch Fälle, bei denen Git nicht mehr in der Lage ist, automatisch die Dateien zusammenzuführen, zum Beispiel wenn eine Änderung an der gleichen Stelle einer Datei in beiden Branches vorgenommen wird. Gehen wir vom Beispiel oben aus, die Story, die man da umsetzt, macht auch etwas mit dem Dashboard, welches wir kurzum anpassen mussten:
|
|
Git konnte nicht automatisch mergen und hat somit keinen commit erstellt. Wir müssen den Mergekonflikt von Hand lösen, bevor wir weiter arbeiten können. Weitere Infos liefert git status
:
|
|
Git fügt automatisch eine Markierung in die Dateien ein, welche gmerged werden müssen:
|
|
Das bedeutet, dass der HEAD (also der Masterbranch, weil auf den haben wir vor dem Mergen gewechselt) den oberen Teil (also immer alles auf Grün) und unsere neuen Änderungen den unteren Teil auf dieser Zeile hatten. Man kann den Konflikt nun lösen, indem man den ganzen Block mit der gewünschten Änderung ersetzt. In unserem Beispiel könnte dies "color": "auto",
sein, da wir in der Story was umgesetzt haben, dass die Farbe automatisch richtig gewählt wird, uns jedoch dank dem Mergekonflikt aufgefallen ist, dass wir ein Koma vergessen haben. Ist der Konflikt gelöst, können wir die Datei ganz normal stagen und commiten. Gerade bei grösseren Mergekonflikten kann es praktisch sein, mit tools zu Arbeiten, welche einem die Unterschiede zwischen den beiden Branches grafisch darstellen. Dafür gibt es den Befehl git mergetool
.