Verteiltes Arbeiten mit Git: Wie Teams die richtige Strategie finden​

Seite 2: Fazit: Ist sich das Team einig, gelingt auch die Strategie

Inhaltsverzeichnis

Ein reibungsloser Entwicklungsprozess lässt sich unabhängig von der gewählten Git-Strategie nur dann gewährleisten, wenn sich das gesamte Team auf eine klar definierte Vorgehensweise einigt – oder diese zumindest jedem Teammitglied erklärt wurde. Nur so ist verlässlich sichergestellt, dass alle dieselben Grundfunktionen von Git nutzen. Das erleichtert die Fehlersuche und das Interpretieren von Logs. Code-Merger gestalten sich einheitlich und laufen weniger zeitaufwendig ab. Auch lassen sich "Git-Alleingänge" verhindern, bei denen Teammitglieder am Ende eines Sprints in einem undurchsichtigen Prozess alle Änderungen zusammenführen.

Die vorgestellten Strategien folgen einer Reihe von Best Practices, darunter häufiges Aktualisieren des eigenen Arbeitsstands, etwa durch Rebase beim GitHub Flow und GitLab Flow oder durch häufiges Pushen und Pullen bei TBD. Diese Vorgehensweise bewahrt vor dem gefürchteten "Big Bang Merge" am Ende eines Sprints, bei dem Entwickler verschiedene, komplett voneinander unabhängig entwickelte Code-Änderungen unter Zeitdruck zusammenführen. Stattdessen fließen die Änderungen zum frühestmöglichen Zeitpunkt in den Main Branch zurück, von wo andere Teammitglieder diese über einen täglichen Rebase in ihren Code integrieren. Ihre Änderungen bauen somit organisch auf den neu zusammengeführten Codeabschnitten auf. Merge-Konflikte lassen sich in vielen kleinen Schritten über den Sprint verteilt lösen, anstatt in einem großen Konflikt zu münden. Davon profitiert das gesamte Entwicklungsteam, Code wird stabiler und der mit Merges verbundene Stress sinkt.

Tabelle 2: Strategien im Vergleich
Strategie Trennung von Entwickler & Code Multiple Versionen Einzelne Versionen Hohe Erfahrung & Testabdeckung
GitHub Flow Hoch Nein Ja Nein
GitLab Flow Hoch Ja Nein Nein
Trunk-based Development Niedrig Ja Ja Ja
GitHub Flow, GitLab Flow und Trunk-based Development zeichnen sich durch individuelle Vor- und Nachteile aus. Die Tabelle fasst sie zusammen und stellt sie gegenüber.
Git-Strategien bewerten​

Beim Bewerten noch unbekannter Strategien helfen die folgenden Best Practices:

Anzahl langlebiger Branches minimieren: Langlebige parallele Branches müssen immer wieder synchronisiert werden. Ihre Existenz erhöht somit den Git-Verwaltungsaufwand erheblich. Idealerweise beschränkt sich eine Git-Strategie auf einen einzelnen langlebigen Branch: den Main Branch. Zusätzliche langlebige Branches sollten demnach signifikante Vorteile aufweisen, um überleben zu dürfen.

Lebensdauer kurzlebiger Branches reduzieren: Je länger ein Feature Branch existiert, desto länger werden Änderungen isoliert vom Rest des Teams entwickelt. Durch einen Neuaufbau auf dem Main Branch kann sich ein Entwickler zwar Updates auf den Feature Branch holen, muss aber potenziell jedes Mal Merge-Konflikte lösen. Für den Rest des Teams gibt es allerdings kein Äquivalent, was bedeutet, dass Teammitglieder sich nicht auf die gerade auf einem Feature Branch entwickelten Änderungen einstellen können. Deshalb sollte die Existenz kurzlebiger Branches von einer Git-Strategie nicht unnötig gestreckt werden.

Häufig aktualisieren: Ab dem Abzweigen eines Branch(es) von einem anderen nehmen die Unterschiede mit jedem Commit zu. Wenn Entwickelnde über längere Zeit hinweg isoliert an einem Feature arbeiten, ist die Chance sehr groß, dass bei dem Versuch eines Merge des Features in den Main Branch ein größerer, komplizierterer Merge-Konflikt entsteht. Das lässt sich nur durch möglichst tägliches Aktualisieren der Branches verhindern. Typischerweise gelangt der neue Stand des Main Branch entweder per Rebase oder Merge in den Feature Branch. Die Entwicklung findet nicht mehr gegen einen veralteten Stand statt. Außerdem teilen sich große, komplexe Merge-Konflikte am Ende in kleinere und simplere auf.

Codequalität maximieren: In den meisten Strategien dient der Main Branch als Grundlage für Releases und neue Branches. Daher muss der Code, der in den Main Branch integriert wird, eine besonders hohe Qualität haben. Somit können sich alle Entwickelnden sicher sein, dass der Startpunkt für ihre Änderungen stabil ist. Es bietet sich daher an, die Qualitätssichernden vor einem Merge auf Main zu platzieren.

Alte Geister, neue Anti-Pattern oder Lösungen für ein bestimmtes Problem: Es gibt noch einige weitere bekannte Git-Strategien.

Beim GitLab Flow mit Environment Branches wird für jede Umgebung – Dev, Test, Staging und Production – ein eigener Git-Branch erstellt und Änderungen in der logischen Reihenfolge von einem in den nächsten Branch überführt.

Der vermeintliche Vorteil ist, dass in jeder Umgebung stets der aktuelle Code verfügbar ist. Allerdings erfordern dedizierte Branches pro Umgebung auch, dass die Anwendung pro Umgebung erneut gebaut wird. Selbst wenn der Code sich nach einem Merge, etwa von der Test- zur Staging-Stufe, nicht ändert: Es ist schwierig bis unmöglich, das exakt selbe Artefakt zu erhalten. Im schlimmsten Fall wird damit eine Version, die auf der Staging-Umgebung 100 Prozent der Tests erfolgreich absolviert hat, auf der Produktionsumgebung zu einem Crash führen, weil das Executable zwar aus demselben Code erstellt wurde, aber zu unterschiedlichen Zeiten zu unterschiedlichen Ergebnissen geführt hat.

Sinnvoller ist daher das Prinzip "build once, deploy everywhere". Sprich: Das Executable exakt einmal zu bauen und dann anschließend schrittweise auf verschiedene Umgebungen auszurollen. Dadurch ist nicht nur garantiert, dass das in Produktion ausgerollte Executable exakt der in der Staging-Umgebung getesteten entspricht. Es sinkt auch der Git-Verwaltungsaufwand, weil nicht mehr für eine Änderung mindestens drei Merges durchzuführen sind.

Der Git Flow ist eine ehemals sehr beliebte Strategie, die die Trennung zwischen Entwicklungs- und Produktionscode in den Vordergrund stellt. Parallel zum Main Branch existiert ein Develop Branch. Entwickler zweigen Feature Branches vom Develop Branch ab und führen Änderungen in diesen zurück. Steht ein Release an, wird vom Develop Branch ein Release Branch abgezweigt, auf dem finale Änderungen wie das Anpassen von Versionsnummern vorgenommen werden. Diese ziehen Entwickler dann sowohl in den Develop Branch als auch in den Main Branch. Ein Tag auf dem Main Branch hält den Stand der Version fest.

Der Verwaltungsaufwand bei dieser Strategie ist beachtlich, da zwei parallele Branches über die gesamte Dauer des Projekts existieren und ein direkter Merge von dem einen in den anderen nicht erlaubt ist. Stattdessen bedarf es eines Hilfs-Branch, der wiederum in zwei Branches integriert werden muss. Eine solche extreme Abgrenzung von Entwicklungs- und Produktionscode bietet nur geringen Mehrwert. Auf der Habenseite gewährt sie zusätzliche Punkte, um Kontrollen und andere Qualitätssicherungsmaßnahmen durchführen zu können. Ob diese zusätzliche Fehler aufdecken, die bei Pull Requests von den Feature Branches oder bei automatisierten Builds von Develop nicht bereits aufgefallen sind, ist fraglich.

Ein weiteres Problem ist das Missverständnis, dass die Tags des Main Branch mehrere parallele Versionen erlauben. Zwar lässt sich theoretisch von einem Tag ein Branch abzweigen, aber es existiert kein sinnvolles Ziel, um die Änderungen wieder zu einem Release zu führen. Denn der Develop Branch wird bereits neue Features enthalten und es ist nicht zulässig, ihn direkt in den Main Branch zu mergen. Selbst wenn es erlaubt wäre, hätte dieser potenziell bereits neue Merges erhalten, die neue Versionen repräsentieren. Dementsprechend leistet diese Strategie kaum mehr als der GitHub Flow, führt aber zu einem Vielfachen an Verwaltungsaufwand.

Das Forking ist als Strategie unerlässlich für die Open-Source-Community. Schließlich kämpfen Open-Source-Projekte mit Problemen, die in der industriellen Programmierung nahezu unbekannt sind: anonyme und ständig wechselnde Entwickler. Während in der Industrie meist eine Person die mit On- und Offboarding von Kollegen anfallenden Berechtigungsänderungen überblicken kann, haben bekannte Open-Source-Projekte bis zu Tausende Mitwirkende. Wenn das Kern-Team des Projekts die Rechte für jede Person verwalten müsste, käme das Projekt recht schnell zum Erliegen.

Um dieses Problem zu lösen, dürfen Mitwirkende grundsätzlich das Repository nur anschauen, aber nicht verändern. Sie dürfen allerdings jederzeit einen Fork erstellen, also eine private Kopie des Repositories. Darin verfügen sie über administrative Berechtigungen. Nehmen sie Änderungen vor, die zum Ursprungsprojekt beitragen sollen, stellen sie einen Pull Request. Das Kern-Team prüft die Anfrage und kann dann die Änderungen bei Bedarf in das Ur-Repository integrieren. Somit muss sich das Kern-Team nicht mit dem Rechte-Management beschäftigen.

(map)