Hat ein Entwicklungsteam den zentralisierten Git-Workflow einmal adaptiert, ist es nicht schwer, Feature-Branches in den Entwicklungsprozess zu integrieren, um die Zusammenarbeit zu intensivieren und die Kommunikation zwischen den Entwicklern zu straffen.
Der Feature-Branch-Workflow
Hat ein Entwicklungsteam den zentralisierten Git-Workflow einmal adaptiert, ist es nicht schwer, Feature-Branches in den Entwicklungsprozess zu integrieren, um die Zusammenarbeit zu intensivieren und die Kommunikation zwischen den Entwicklern zu straffen.
Die Kernidee hinter dem Feature-Branch-Workflow ist die, dass die Feature-Entwicklung in dedizierten Branches stattfinden sollte und nicht im Master-Branch. Diese Abkapselung macht es einfach, mit mehreren Entwicklern an einem bestimmten Feature zu arbeiten, ohne die Haupt-Codebasis zu beeinflussen. Und das bedeutet auch, dass der Master-Branch niemals fehlerhaften Code enthalten wird – in Continuous-Integration-Umgebungen ein enormer Vorteil.
Das Abkapseln der Feature-Entwicklung macht es zudem möglich, Pull-Requests wirksam einzusetzen, die eine ausgezeichnete Möglichkeit bieten, Diskussionen im Hinblick auf den Branch zu initiieren. Sie geben anderen Entwicklern die Chance, ein Feature “abzusegnen”, bevor es in das offizielle Projekt integriert wird. Oder ein Entwickler, der mitten in einem Feature festhängt, kann eine Pull-Request stellen, um sich Rat und Ideen von Kollegen zu holen. Kurzum: Pull-Requests machen es wirklich einfach, die Arbeit eines anderen im Team zu kommentieren.
Feature-Branches
Auch der Feature-Branch-Workflow nutzt eine zentrale Repository, der Master repräsentiert auch hier die offizielle Projekt-History. Doch statt direkt in den lokalen Master-Branch zu committen, erzeugen Entwickler jedes Mal, wenn sie mit einem neuen Feature beginnen, neue Branches. (Feature-Branches sollten daher aussagefähige Namen wie objekte-animiertes-menue
oder vorgang-#1034
haben, damit für jeden Branch klar ersichtlich ist, welchen Zweck er hat.)
Git macht keine technischen Unterscheidungen zwischen dem Master-Branch und Feature-Branches: Entwickler können editieren, stagen und Änderungen in einen Feature-Branch committen, wie es sie es vom zentralisierten Workflow kennen.
Zusätzlich können (und sollten) Feature-Branches in die zentrale Repository gepusht werden. Dadurch ist es möglich, ein Feature mit anderen Entwicklern zu teilen, ohne irgendwelchen offiziellen Code zu berühren. Da der Master der einzige “spezielle” Branch ist, wirft das Speichern diverser Features in der zentralen Repository keinerlei Probleme auf. Natürlich ist das auch ein bequemer Weg, Backups aller lokalen Commits zu erstellen.
Pull-Requests
Abgesehen von der Feature-Entwicklung ans sich ermöglichen es Branches, Änderungen mithilfe von Pull-Requests zu diskutieren. Hat jemand ein Feature fertiggestellt, mergt er es nicht sofort in den Master-Branch. Stattdessen pusht er den Feature-Branch in den zentralen Server und schickt eine Pull-Request mit der Bitte um Anmerkungen in den Master. Das gibt anderen Entwicklern die Möglichkeit, Änderungen gegenzuprüfen, ehe sie Bestandteil der Haupt-Codebasis werden.
Das Reviewen von Code ist ein wesentlicher Vorteil von Pull-Requests, doch in erster Linie sind sie dazu da, einen generischen Weg zu bieten, über Code zu reden. Pull-Requests kann man sich am besten als Diskussionen vorstellen, die sich um einen bestimmten Branch drehen. Sie können also frühzeitig im Entwicklungsprozess genutzt werden, und zwar weit bevor es fertige Features zu reviewen gibt.
Braucht ein Entwickler beispielsweise Unterstützung bei einem bestimmten Feature, muss er einfach nur eine Pull-Request absetzen. Interessierte Kollegen werden automatisch benachrichtigt und können die Frage direkt neben den relevanten Commits einsehen.
Sobald eine Pull-Request akzeptiert wurde, ist der Akt der Veröffentlichung eines Features fast derselbe wie beim zentralisierten Workflow. Der lokale Master muss mit dem Upstream-Master synchronisiert sein, dann wird der Feature-Branch in den Master gemergt und der aktualisierte Master zurück in die zentrale Repository gepusht.
Teams, die diesen Workflow adaptieren, werden schnell erkennen, wie Feature-Branches die Funktionalitäten des einzelnen Master-Branchs, der im zentralisierten Workflow genutzt wird, multiplizieren. Darüber hinaus fördern Feature-Branches Pull-Requests, die es ermöglichen, spezifische Commits direkt im Repository-Managementsystem zu diskutieren. Der Feature-Branch-Workflow ist ein wirklich flexibler Weg, um Projekte zu entwickeln. Er kann allerdings auch zu flexibel sein. In großen Teams ist es oft vorteilhaft, verschiedenen Branches spezifischere Rollen zuzuweisen. Hier setzt der Gitflow-Workflow an.
Beispiel
Ehe Entwickler A mit der Entwicklung eines Features beginnt, braucht er einen isolierten Branch, an dem er arbeiten kann. Der Git-Befehl hat diese Form:
git checkout -b entwickler-a-feature master
Dadurch wird ein Branch namens entwickler-a-feature
erzeugt, der auf dem Master-Branch basiert. -b
weist Git an, den Branch zu erstellen, sofern er noch nicht existiert. In diesem Branch kann Entwickler A nun wie üblich editieren, stagen und Änderungen committen und sein Feature mit so vielen Commits wie erforderlich bauen:
git status
git add <some-file>
git commit
Entwickler A fügt seinem Feature im Verlauf des Vormittags ein paar Commits hinzu. Bevor er zum Mittagessen geht, hält er es für eine gute Idee, sein Feature hoch in die zentrale Repository zu pushen. Das ist eine praktische Backup-Möglichkeit, doch wenn A mit anderen Entwicklern zusammenarbeiten würde, bekämen diese damit ebenfalls Zugriff auf seine initialen Commits:
git push -u origin entwickler-a-feature
Der Befehl pusht entwickler-a-feature
in die zentrale Repository (origin
). -u
fügt ihn als einen Remote-Tracking-Branch hinzu. Nach dem Aufsetzen des Tracking-Branchs kann A git push
ohne weitere Parameter ausführen, um sein Feature zu pushen.
Nach der Mittagspause stellt A sein Feature fertig. Ehe er es in den Master-Branch mergt, muss er eine Pull-Request stellen, damit der Rest des Teams weiß, dass er soweit ist. Doch zunächst soll sichergestellt sein, dass die zentrale Repository die neuesten Commits hat:
git push
Dann speichert er die Pull-Request mit der Bitte, entwickler-a-feature
in den Master zu mergen, in der Git-Oberfläche, und die anderen Teammitglieder erhalten automatische Benachrichtigungen. Das Schöne an Pull-Requests ist, dass sie Kommentare direkt neben dem entsprechenden Commits anzeigen. Es ist also einfach, Fragen zu einem spezifischen Zusammenhang zu stellen.
Entwickler B erhält die Pull-Request und schaut sich entwickler-a-feature
an. Er ist der Meinung, dass ein paar Änderungen vorgenommen werden sollten, ehe das Feature ins offizielle Projekt integriert wird; in diesem Zusammenhang haben B und A einen Austausch via Pull-Request.
Um die Änderungen vornzunehmen, folgt Entwickler A exakt demselben Prozess wie bei der ersten Iteration seines Features. Er editiert, stagt, committet und pusht Aktualisierungen in die zentrale Repository. Alles, was er tut, wird in der Pull-Request abgebildet, und Entwickler B kann alles kommentieren.
Wenn er wollte, könnte Entwickler B selbst entwickler-a-feature
in seine lokale Repository ziehen und seinerseits daran arbeiten. All seine hinzugefügten Commits würden ebenfalls in der Pull-Request abgebildet werden.
Nachdem Entwickler B die Pull-Request akzeptiert hat, muss jemand das Feature in das stabile Projekt mergen. Das können sowohl A oder B tun:
git checkout master
git pull
git pull origin entwickler-a-feature
git push
Zunächst muss, wer immer auch den Merge durchführt, seinen Master-Branch auschecken und sicherstellen, dass er aktuell ist. Dann mergt git pull origin entwickler-a-feature
die Kopie von entwickler-a-feature
in der zentralen Repository. Dieser Befehl stellt sicher, dass immer die aktuellste Version des Feature-Branchs gemergt wird. Zum Schluss muss der aktualisierte Master zurück zur origin
gepusht werden.
Das Ergebnis dieses Prozesses ist oft ein Merge Commit. Einige Entwickler mögen das, denn es ist wie das symbolische Hinzufügen eines Features zum Rest der Codebasis. Doch wenn man eine lineare History bevorzugt, ist es möglich, ein Rebasing des Features obenauf auf den Master durchzuführen, bevor der Merge intitiiert wird. Resultat ist ein Merge im Schnellverfahren.
Einige Repository-Managementsysteme automatisieren den Prozess, die Pull-Request zu akzeptieren, indem all diese Befehle durch einen einfachen Klick auf einen entsprechenden Akzeptieren-Button ausgelöst werden. Wenn ein System dies nicht unterstützt, sollte es zumindest die Pull-Request schließen, wenn das Feature in den Master gemergt wird.
Derweil macht Entwickler C das gleiche
Während A und B an entwickler-a-feature
arbeiten und in der Pull-Rquest darüber diskutieren, macht Entwickler C das gleiche mit seinem eigenen Feature-Branch. Durch das Isolieren von Features in separaten Branches kann jeder unabhängig arbeiten – und dennoch ist es simpel, Änderungen wenn nötig mit anderen Entwicklern zu teilen.