Bei der Vielzahl möglicher Workflows ist es nicht leicht, einen Anfang zu finden, wenn man Git in der Arbeitsumgebung implementieren möchte. Diese Seite gibt einen Überblick über die gängigsten Git-Workflows für Enterprise-Teams und bietet so einen ersten Ansatzpunkt.

Beachte im Folgenden, dass diese Workflows mehr als Richtlinien und weniger als konkrete Regeln dienen sollen. Wir möchten dir Möglichkeiten aufzeigen, sodass du die Vorteile der verschiedenen Workflows so nutzen kannst, wie es zu deinen individuellen Anforderungen passt.

Zentraler Workflow

Git-Workflows: SVN-basierte Workflows

Die Umstellung auf ein verteiltes Versionskontrollsystem mag kompliziert erscheinen. Du kannst Git jedoch nutzen, ohne deinen aktuellen Workflow verändern zu müssen. Dein Team kann Projekte exakt so entwickeln wie mit Subversion.

Gegenüber SVN hat Git für den Entwicklungs-Workflow jedoch eine ganze Reihe von Vorteilen. Zunächst hat jeder Entwickler eine eigene lokale Kopie des gesamten Projekts zur Verfügung. In dieser isolierten Umgebung kann er unabhängig von seinen Kollegen arbeiten, ohne Rücksicht auf deren Änderungen am Projekt nehmen zu müssen. Commits werden dem lokalen Repository hinzugefügt und Upstream-Änderungen erst einbezogen, wenn er dazu bereit ist.

Zum anderen erhältst du Zugriff auf das solide Branching- und Merging-Modell von Git. Im Gegensatz zu SVN sind Git-Branches darauf ausgelegt, einen störungssicheren Mechanismus zur Code-Integration und zum Teilen von Änderungen zwischen verschiedenen Repositorys zu ermöglichen.

Wie es funktioniert

Ganz wie in Subversion arbeitest du auch im zentralisierten Workflow mit einem zentralen Repository, in dem alle Änderungen am Projekt gespeichert werden. Dabei heißt der standardmäßige Entwicklungs-Branch nicht trunk, sondern master. In ihn werden sämtliche Änderungen committet. Andere Branches als master werden in diesem Workflow nicht benötigt.

Jeder Entwickler klont zunächst das zentrale Repository. Anschließend bearbeitet er die Dateien in seiner lokalen Kopie des Projekts und committet seine Änderungen wie in SVN. Der einzige Unterschied ist, dass die neuen Commits lokal gespeichert werden, vollständig isoliert vom zentralen Repository. Eine Upstream-Synchronisierung wird erst dann durchgeführt, wenn der Entwickler es für angebracht hält.

Sollen die Änderungen im offiziellen Projekt veröffentlicht werden, pusht der Entwickler seinen lokalen Branch master in das zentrale Repository. Dieser Vorgang entspricht svn commit, fügt jedoch alle lokalen Commits hinzu, die nicht bereits im zentralen Branch master abgelegt sind.

Zentrale und lokale Repositorys

Konflikte beheben

Das zentrale Repository stellt das offizielle Projekt dar. Deshalb sollte dessen Commit-Verlauf als unveränderlich betrachtet werden. Wenn die lokalen Commits eines Entwicklers vom zentralen Repository abweichen, verhindert Git, dass Änderungen an ihnen verschoben werden, um das Überschreiben offizieller Commits zu verhindern.

Konflikte beheben

Bevor der Entwickler ein Feature veröffentlichen kann, muss er die aktuellen zentralen Commits abrufen und seine Änderungen voranstellen. Er könnte also sagen: "Ich möchte auf der Arbeit der anderen aufbauen und meine Änderungen hinzufügen." Als Ergebnis entsteht ein absolut linearer Verlauf, genau wie in herkömmlichen SVN-Workflows.

Sollten lokale Änderungen in direktem Konflikt mit Upstream-Commits stehen, stoppt Git den Rebase-Prozess. Du hast dann die Möglichkeit, die Konflikte manuell zu lösen. Ein Vorteil von Git: Mit den Befehlen git status und git add kannst du nicht nur Commits erzeugen, sondern auch Merge-Konflikte lösen. Neue Entwickler können ihre Merges auf diese Weise unkompliziert selbst verwalten. Sollten sie doch auf Probleme stoßen, können sie ebenso einfach den gesamten Rebase abbrechen und es nochmals versuchen (oder sich Unterstützung holen).

Beispiel

Wir wollen nun Schritt für Schritt veranschaulichen, wie die Zusammenarbeit eines typischen kleinen Teams mit diesem Workflow aussieht. Wir zeigen, wie zwei Entwickler – nennen wir sie John und Mary – an separaten Features arbeiten und über ein zentrales Repository ihre Beiträge teilen.

Jemand legt das zentrale Repository an

Git-Workflows: Zentrales Bare-Repository anlegen

Zunächst muss jemand das zentrale Repository auf einem Server anlegen. Handelt es sich um ein neues Projekt, kannst ein leeres Repository anlegen. Andernfalls muss du ein vorhandenes Git- oder SVN-Repository importieren.

Zentrale Repositorys sollten immer Bare-Repositorys sein (sie sollten kein Arbeitsverzeichnis haben). Du kannst sie folgendermaßen erstellen:

ssh user@host git init --bare /path/to/repo.git

Gib dabei einen gültigen SSH-Benutzernamen für user, die Domäne oder die IP-Adresse deines Servers für host und den gewünschten Speicherort deines Repositorys für /path/to/repo.git an. Es ist Konvention, die Erweiterung .git an den Repository-Namen anzuhängen, um das Repository als Bare-Repository zu kennzeichnen.

Jeder klont das zentrale Repository

Git-Workflows: Zentrales Repository klonen

Im nächsten Schritt erstellt jeder Entwickler eine lokale Kopie des gesamten Projekts. Dazu dient der Befehl git clone:

git clone ssh://user@host/path/to/repo.git

Wird ein Repository geklont, fügt Git automatisch eine Verknüpfung mit dem Namen origin hinzu, die auf das Ursprungs-Repository verweist. So kannst du später mit diesem Repository interagieren.

John arbeitet an seinem Feature

Git-Workflows: Feature-Prozess: bearbeiten, auf Staging-Ebene verschieben, committen

John kann mit dem standardmäßigen Commit-Prozess in Git – bearbeiten, auf die Staging-Ebene verschieben und committen – in seinem lokalen Repository Features entwickeln. Falls du mit der Staging-Umgebung nicht vertraut bist, solltest du wissen, dass sie eine Möglichkeit bietet, einen Commit vorzubereiten, ohne dabei jede einzelne Änderung dem Arbeitsverzeichnis hinzufügen zu müssen. So kannst du, auch wenn du viele lokale Änderungen vorgenommen hast, sehr fokussierte Commits erstellen.

git status # Repository-Zustand anzeigen
git add <eine-datei> # Eine Datei in die Staging-Umgebung verschieben
git commit # Eine Datei committen </eine-datei>

Du erinnerst dich sicher, dass mit diesen Befehlen lokale Commits erstellt werden. Daher kann John diesen Prozess so oft wiederholen wie er will, ohne sich darum kümmern zu müssen, was im zentralen Repository passiert. Das kann sehr nützlich sein bei umfangreichen Features, die in einfachere und kleinere Teile zerlegt werden müssen.

Mary arbeitet an ihrem Feature

Git-Workflows: Feature: bearbeiten, auf Staging-Ebene verschieben, committen

Mary arbeitet parallel an einem eigenen Feature in ihrem lokalen Repository und nutzt dazu denselben Prozess nach dem Muster "Bearbeitung/Staging/Commit". Ganz wie John kann sie dabei das zentrale Repository vollständig ignorieren. Auch die Änderungen, die John in seinem lokalen Repository vornimmt, sind für sie vollkommen unwichtig, da alle lokalen Repositorys privat sind.

John veröffentlicht sein Feature

Git-Workflows: Features veröffentlichen

Sobald John sein Feature abgeschlossen hat, sollte er seine lokalen Commits auf dem zentralen Repository veröffentlichen, damit andere Teammitglieder darauf zugreifen können. Dies kann er über den Befehl git push erreichen:

git push origin master

Denke daran, dass es sich bei origin um die Remote-Verbindung zum zentralen Repository handelt, das mit Git erstellt wurde, als John es geklont hat. Das master-Argument weist Git an, den master-Branch von origin so aussehen zu lassen wie seinen lokalen master-Branch. Da das zentrale Repository nicht mehr aktualisiert wurde, seit John es geklont hat, wird es keine Konflikte geben und der Push-Vorgang erwartungsgemäß verlaufen.

Mary versucht ihr Feature zu veröffentlichen

Git-Workflows: Fehler beim Verschieben von Befehlen

Sehen wir uns mal an, was passiert, wenn Mary ihr Feature versucht zu verschieben, nachdem John seine Änderungen in das zentrale Repository verschoben hat. Sie kann haargenau denselben Befehl zum Verschieben nutzen:

git push origin master

Doch ihr lokaler Verlauf weicht vom zentralen Repository ab. Deshalb lehnt Git den Request ab und zeigt eine längere Fehlermeldung an:

error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

So wird Mary daran gehindert, offizielle Commits zu überschreiben. Sie muss die Aktualisierungen von John in ihr Repository verschieben, ihre lokalen Änderungen implementieren und es noch einmal versuchen.

Mary stellt Johns Commit(s) ihre Änderungen voran.

Git-Workflows: Rebasing mit git pull

Mary kann git pull verwenden, um Upstream-Änderungen in ihr Repository zu integrieren. Dieser Befehl ist svn update ähnlich – damit wird der gesamte Upstream-Commit-Verlauf in Marys lokales Repository gepullt und versucht, ihn in ihre lokalen Commits zu integrieren:

git pull --rebase origin master

Die Option --rebase weist Git an, alle Commits von Mary zur Spitze des master--Branch zu verschieben, nachdem dieser mit den Änderungen aus dem zentralen Repository synchronisiert wurde, wie unten gezeigt:

Rebasing zum Master-Repository

Das Verschieben würde auch ohne diese Option funktionieren. Dann würdest du aber jedes Mal, wenn jemand eine Synchronisierung mit dem zentralen Repository durchführen muss, einen überflüssigen "Merge-Commit" erzeugen. Für diesen Workflow eignet sich das Rebasing immer besser als ein Merge-Commit.

Mary löst einen Merge-Konflikt

Git-Workflows: Rebasing von Commits

Das Rebasing erfolgt, indem jeder lokale Commit einer nach dem anderen an den aktualisierten master-Branch übertragen wird. Das bedeutet, dass du Merge-Konflikte für jeden einzelnen Commit erfasst, anstatt alle gleichzeitig in einem massiven Merge-Commit zu lösen. Dadurch bleiben deine Commits weitestgehend fokussiert, was zu einem sauberen Projektverlauf führt. Das macht es wiederum wesentlich einfacher herauszufinden, wo Bugs entstanden sind und ob Änderungen mit minimalen Auswirkungen auf das Projekt zurückgesetzt werden können.

Wenn Mary und John an nicht ähnlichen Features arbeiten, sind Konflikte durch den Rebasing-Prozess unwahrscheinlich. Kommt es dennoch zu Konflikten, hält Git das Rebasing bei dem aktuellen Commit an und gibt folgende Meldung zusammen mit einigen relevanten Anweisungen aus:

CONFLICT (content): Merge conflict in <eine-datei>
Lösung des Konflikts

Das Tolle an Git ist, dass jeder seine eigenen Merge-Konflikte lösen kann. In unserem Beispiel würde Mary einfach den Befehl git status ausführen, um festzustellen, wo das Problem liegt. In Konflikt stehende Dateien werden im Abschnitt mit nicht zusammengeführten Pfaden angezeigt:

# Nicht gemergte Pfade:
# (verwende zum Verschieben in die Staging-Umgebung "git reset HEAD <eine-datei>...")
# (verwende "git add/rm <eine-datei>..." zur Kennzeichnung der Lösung)
#
# beide geändert: <eine-datei>

Danach wird sie die Datei(en) entsprechend ihren Anforderungen bearbeiten. Wenn sie mit dem Ergebnis zufrieden ist, kann sie die Datei(en) wie üblich stagen, den Rest erledigt dann git rebase:

git add <eine-datei>
git rebase --continue

Und das war's schon. Git fährt mit dem nächsten Commit fort und wiederholt den Prozess für alle anderen Commits, die Konflikte erzeugen.

Wenn du an dieser Stelle feststellst, dass du keine Ahnung hast, worum es geht, keine Sorge. Führe einfach den folgenden Befehl aus und du wirst wieder dort landen, wo du angefangen hast, bevor du [git pull --rebase](/tutorials/syncing/git-pull) ausgeführt hast:

git rebase --abort

Mary veröffentlicht erfolgreich ihr Feature

Git-Workflows: Zentrales Repository synchronisieren

Nachdem Mary die Synchronisierung mit dem zentralen Repository abgeschlossen hat, kann sie ihre Änderungen erfolgreich veröffentlichen:

git push origin master

Wie geht es weiter?

Wie du siehst, kann man mit ein paar Git-Befehlen die herkömmliche Entwicklungsumgebung einer Subversion replizieren. Das ist gut, wenn Teams die Umstellung von SVN durchführen wollen. Doch dabei kommen die Möglichkeiten, die Git zur verteilten Zusammenarbeiten bietet, nicht zum Einsatz.

Wenn dein Team mit dem zentralisierten Workflow einigermaßen vertraut ist, aber lieber seine Zusammenarbeit optimieren möchte, solltest du auf jeden Fall einmal die Vorteile des Feature-Branch-Workflow ansehen. Wenn jedem Feature ein isolierter Branch zugewiesen wird, können ausführliche Diskussionen über neue Ergänzungen angestoßen werden, bevor diese in das offizielle Projekt integriert werden.

Feature Branch Workflow

Feature Branch Workflow

Sobald du dich mit dem zentralisierten Workflow auskennst, ist es ganz einfach, deinem Entwicklungsprozess feature-Branches hinzuzufügen, um die Zusammenarbeit zu fördern und die Kommunikation zwischen Entwicklern zu optimieren.

Die Grundidee hinter dem Feature-Branch-Workflow ist, dass die gesamte Feature-Entwicklung in einem dedizierten Branch und nicht in einem master-Branch stattfinden sollte. Diese Einkapselung erleichtert mehreren Entwicklern die Arbeit an einem bestimmten Feature, ohne dabei die Haupt-Codebasis zu stören. Außerdem wird der master-Branch dadurch niemals beschädigten Code enthalten, was für Continuous-Integration-Umgebungen ein immenser Vorteil ist.

Die Einkapselung der Feature-Entwicklung ermöglicht außerdem die Nutzung von Pull Requests, die ein guter Einstiegspunkt für Diskussionen um Branches sind. Andere Entwickler haben dadurch die Möglichkeit, ein Feature zu genehmigen, bevor es in das offizielle Projekt integriert wird. Oder wenn du mitten in der Feature-Entwicklung nicht mehr weiterweißt, kannst du einen Pull Request starten, um deine Kollegen um Vorschläge zu bitten. Tatsächlichen machen Pull Requests es deinem Team unglaublich einfach, die Arbeit der anderen zu kommentieren.

Wie es funktioniert

Der Feature-Branch-Workflow nutzt immer noch ein zentrales Repository und master steht immer noch für den Verlauf des offiziellen Projekts. Aber anstatt direkt auf ihrem lokalen master-Branch zu committen, erstellen Entwickler jedes Mal einen neuen Branch, wenn sie an einem neuen Feature arbeiten. Feature-Branches sollten beschreibende Namen haben, wie animated-menu-items oder issue-#1061. Dadurch soll jedem Branch ein klarer, deutlich fokussierter Zweck zugewiesen werden.

Git unterscheidet rein technisch nicht zwischen dem master-Branch und feature-Branches, deshalb können Entwickler Änderungen am feature-Branch bearbeiten, stagen und committen, wie sie es im zentralisierten Workflow auch tun würden.

Darüber hinaus können (und sollten) feature-Branches auf das zentrale Repository gepusht werden. Dadurch kann ein Feature mit anderen Entwicklern geteilt werden, ohne dass ein offizieller Code davon berührt wird. Da der master der einzige "besondere" Branch ist, stellt das Speichern mehrerer feature-Branches auf dem zentralen Repository kein Problem dar. Natürlich ist dies auch eine praktische Methode, um die lokalen Commits aller Teammitglieder zu sichern.

Pull Requests

Neben der Isolierung der Feature-Entwicklung erlauben Branches auch Diskussion zu Änderungen mithilfe von Pull Requests. Sobald ein Teammitglied ein Feature fertiggestellt hat, wird dieses nicht sofort in den master gemergt. Stattdessen pusht das Teammitglied den feature-Branch zum zentralen Server, erstellt einen Pull Request und bittet darum, dass die Ergänzungen in den master gemergt werden. Dadurch erhalten andere Entwickler Gelegenheit, die Änderungen zu überprüfen, bevor sie Teil der Haupt-Codebasis werden.

Code-Review ist ein großer Vorteil von Pull Requests. Sie sind jedoch eigentlich dafür gedacht, damit ihr euch über Code austauschen könnt. Du kannst dir Pull Requests als Diskussion über einen bestimmten Branch vorstellen. Das bedeutet auch, dass sie zu einem viel früheren Zeitpunkt im Entwicklungsprozess genutzt werden können. Wenn ein Entwickler beispielsweise bei einem bestimmten Feature Hilfe braucht, muss er nur einen Pull Request senden. Interessierte werden dann automatisch benachrichtigt und können die Frage direkt neben den entsprechenden Commits sehen.

Sobald ein Pull Request akzeptiert wird, läuft die tatsächliche Veröffentlichung eines Features ähnlich ab wie beim zentralisierten Workflow. Zunächst musst du sicherstellen, dass dein lokaler master mit dem Upstream-master synchronisiert ist. Dann mergst du den feature-Branch in den master und pushst den aktualisierten master zurück zum zentralen Repository.

Pull Requests können durch Lösungen für das Management von Produkt-Repositorys vereinfacht werden, wie Bitbucket Cloud oder Bitbucket Server. Lies dir dazu beispielsweise die Dokumentation zu Pull Requests für Bitbucket Server durch.

Beispiel

Das unten stehende Beispiel zeigt einen Pull Request, der als Code-Review dient. Er könnte aber auch viele andere Zwecke erfüllen.

Mary beginnt mit einem neuen Feature

Neuer Feature Branch

Bevor sie mit der Entwicklung eines Features beginnt, braucht Mary einen isolierten Branch, an dem sie arbeiten kann. Sie kann mit dem folgenden Befehl einen neuen Branch anfordern:

git checkout -b marys-feature master

Dadurch wird ein Branch namens marys-feature auf Basis des master ausgecheckt und die Option -b weist Git an, den Branch zu erstellen, sofern er noch nicht vorhanden ist. Auf diesem Branch kann Mary Änderungen wie gewohnt bearbeiten, stagen und committen und ihr Feature mit so vielen Commits erstellen wie nötig:

git status
git add <eine-datei>
git commit

Mary macht Mittagspause

Git-Workflows: Feature-Commits

Mary fügt ihrem Feature am Vormittag einige Commits hinzu. Bevor sie Mittagessen geht, sollte sie ihren feature-Branch zum zentralen Repository pushen. Dies ist ein praktisches Backup; sollte Mary außerdem mit anderen Entwicklern zusammengearbeitet haben, hätten diese jetzt auch Zugriff auf ihre ersten Commits.

git push -u origin marys-feature

Mit diesem Befehl wird marys-feature zum zentralen Repository (origin) gepusht und die Option -u fügt es als Remote-Tracking-Branch hinzu. Nach dem Einrichten des Tracking-Branch kann Mary git push ohne jegliche Parameter zum Pushen ihres Features aufrufen.

Mary schließt ihr Feature ab

Git-Workflows: Pull Request

Wenn Mary vom Mittagessen zurückkommt, stellt sie ihr Feature fertig. Bevor sie es in den master mergt, muss sie einen Pull Request erstellen und den Rest des Teams darüber informieren, dass sie fertig ist. Zunächst sollte sie aber sicherstellen, dass das zentrale Repository ihre neuesten Commits enthält:

git push

Dann erstellt sie den Pull Request in ihrer Git-GUI und bittet darum, marys-feature in den master zu mergen; die Teammitglieder werden darüber automatisch benachrichtigt. Das Tolle an Pull Requests ist, dass gleich neben den zugehörigen Commits Kommentare angezeigt werden, deshalb können ganz einfach Fragen zu spezifischen Changesets gestellt werden.

Bill erhält den Pull Request

Git-Workflows: Pull Requests für Features

Bill erhält den Pull Request und sieht sich marys-feature an. Er möchte einige Änderungen daran vornehmen, bevor er es in das offizielle Projekt integriert, und er und Mary tauschen sich ein wenig über den Pull Request aus.

Mary macht Änderungen

Git-Workflows: In zentrales Repository verschieben

Um Änderungen vorzunehmen, durchläuft Mary genau denselben Prozess, den sie auch zum Erstellen der ersten Iteration ihres Features genutzt hat. Sie bearbeitet, führt Verschiebungen auf die Staging-Ebene durch, committet und verschiebt Aktualisierungen in das zentrale Repository. Alles, was sie tut, wird im Pull Request angezeigt. Bill kann währenddessen weiter Kommentare machen.

Wenn Bill wollte, könnte er marys-feature in sein lokales Repository pullen und selbst daran arbeiten. Commits, die er hinzugefügt hat, würden ebenfalls im Pull Request angezeigt.

Mary veröffentlicht ihr Feature

Einen Feature Branch mergen

Sobald Bill bereit ist, den Pull Request zu akzeptieren, muss das Feature in das stabile Projekt gemergt werden (entweder Bill oder Mary können das tun):

git checkout master
git pull
git pull origin marys-feature
git push

Wer auch immer das Merging durchführt, muss seinen master-Branch auschecken und sicherstellen, dass er aktuell ist. Daraufhin mergt git pull origin marys-feature die Kopie von marys-feature im zentralen Repository. Du könntest auch den einfachen Befehl git merge marys-feature verwenden, aber der oben gezeigte Befehl stellt sicher, dass du immer die aktuelle Version des feature-Branch pullst. Zum Schluss muss der aktualisierte master zurück zu origin gepusht werden.

Dieser Prozess führt häufig zu einem Merge-Commit. Einigen Entwicklern gefällt das, weil es wie eine symbolische Zusammenführung des Features mit dem Rest der Codebasis ist. Wenn dir ein linearer Verlauf eher liegt, ist es möglich, das Feature vor dem Mergen an die Spitze des master zu verschieben, was zu einem Fast-Forward-Merge führt.

Einige GUIs automatisieren den Genehmigungsprozess von Pull Requests, indem alle diese Befehle einfach durch Klicken auf die Schaltfläche "Akzeptieren" ausgeführt werden. Wenn deine das nicht tut, sollte sie zumindest in der Lage sein, den Pull Request automatisch abzuschließen, wenn der feature-Branch in den master gemergt wird.

Währenddessen macht John genau dasselbe

Während Mary und Bill an marys-feature arbeiten und diese Arbeit in ihrem Pull Request besprechen, tut John genau dasselbe mit seinem eigenen feature-Branch. Indem er Features in einzelnen Branches isoliert, kann jeder unabhängig arbeiten; trotzdem können Änderungen bei Bedarf weiterhin ganz einfach mit anderen Entwicklern geteilt werden.

Wie geht es weiter?

Eine Erläuterung zum Feature-Branching auf Bitbucket findest du in der Dokumentation zur Verwendung von Git-Branches. An dieser Stelle solltest du erkennen können, warum feature-Branches eine Möglichkeit sind, um die Funktionalität des einzelnen master-Branch, der im zentralisierten Workflow verwendet wird, buchstäblich zu vervielfachen. Darüber hinaus vereinfachen feature-Branches auch Pull Requests, sodass spezifische Commits gleich in deiner GUI zur Versionskontrolle diskutiert werden können.

Der Feature Branch Workflow bietet bei der Entwicklung eines Projekts unglaubliche Flexibilität. Allerdings ist die Flexibilität manchmal zu groß. Für größere Teams ist es oft von Vorteil, verschiedenen Branches spezifischere Rollen zuzuweisen. Der Git-flow-Workflow ist ein gängiges Muster zum Managen der Feature-Entwicklung, zum Vorbereiten von Releases und zur Wartung.

Git-flow-Workflow

Git-flow-Workflow

Der folgende Abschnitt zum Gitflow-Workflow stammt von Vincent Driessen bei nvie.

Der Gitflow-Workflow definiert ein strenges Branching-Modell, das um den Release des Projekts konzipiert wurde. Er ist sicherlich komplexer als der Feature-Branch-Workflow, bietet aber einen robusten Rahmen für das Management großer Projekte.

Mit diesem Workflow werden keine neuen Konzepte oder Befehle hinzugefügt, die nicht auch für den Feature Branch Workflow erforderlich sind. Stattdessen werden verschiedenen Branches sehr spezifische Rollen zugewiesen und genau festgelegt, wann und wie die Interaktion aussehen soll. Zusätzlich zu Feature Branches werden einzelne Branches zum Vorbereiten, Warten und Erfassen von Releases verwendet. Dabei kannst du natürlich auch alle Vorteile von Feature Branch Workflows nutzen: Pull Requests, isolierte Tests und eine effizientere Zusammenarbeit.

Wie es funktioniert

Der Gitflow-Workflow nutzt ebenfalls ein zentrales Repository als Kommunikationsdrehkreuz für alle Entwickler. Und wie bei den anderen Workflows arbeiten die Entwickler lokal und pushen Branches in das zentrale Repository. Der einzige Unterschied liegt in der Branch-Struktur des Projekts.

Verlaufs-Branches

Statt eines einzelnen master-Branch sieht dieser Workflow zwei Branches vor, um den Verlauf des Projekts aufzuzeichnen. Der master-Branch enthält den offiziellen Release-Verlauf und der develop-Branch dient als Integrations-Branch für Features. Es ist zudem üblich, alle Commits im master-Branch mit einer Versionsnummer zu taggen.

Verlaufs-Branches

Der übrige Workflow dreht sich um die Unterscheidung zwischen diesen beiden Branches.

Feature Branches

Jedes neue Feature sollte sich auf seinem eigenen Branch befinden, der zu Sicherungs-/Zusammenarbeitszwecken zum zentralen Repository gepusht werden kann. Doch anstatt Branches auf Basis des master zu erstellen, verwenden feature-Branches den develop-Branch als übergeordneten Branch. Wenn ein Feature fertig ist, wird es zurück in den develop-Branch gemergt. Features sollten niemals direkt mit dem master-Branch interagieren.

Feature Branches

Beachte, dass die Kombination von feature-Branches mit dem develop-Branch eigentlich dem Feature-Branch-Workflow entspricht. Doch der Gitflow-Workflow geht darüber hinaus.

Release-Branches

Release-Branches

Wenn der develop-Branch genügend Features für ein Release enthält (oder ein vordefinierter Release-Termin ansteht), wird vom develop-Branch ein Release-Branch geforkt. Damit beginnt der neue Release-Zyklus; in diesem Branch sollten ab diesem Punkt keine neuen Features mehr hinzugefügt werden, sondern nur Bugfixes und ähnliche Release-orientierte Änderungen. Ist es zur Auslieferung bereit, wird das Release in den master gemergt und mit einer Versionsnummer getaggt. Zusätzlich sollte es zurück in den develop-Branch gemergt werden, der sich seit Initiierung des Release weiterentwickelt haben könnte.

Werden Releases in dedizierten Branches vorbereitet, ist paralleles Arbeiten möglich: Eines eurer Teams kann dem aktuellen Release den letzten Schliff geben, während ein anderes Team sich weiter um die Features des nächsten Release kümmert. Außerdem lassen sich auf diese Weise klar abgegrenzte Entwicklungsphasen definieren. Wenn ihr euch entscheidet, in einer Woche an Version 4.0 zu arbeiten, kann die Struktur eures Repositorys diese Entscheidung abbilden.

Gängige Festlegungen:

  • Branchen von: develop
  • Mergen in: master
  • Benennungskonvention: release-* oder release/*

Wartungs-Branches

Wartungs-Branches

Maintenance- oder Hotfix-Branches eignen sich für schnelle Patches von Produktions-Releases. Dies ist der einzige Branch, der direkt vom master geforkt werden sollte. Sobald der Fix abgeschlossen wurde, sollte er sowohl in den master- als auch in den develop-Branch (oder den aktuellen Release-Branch) gemergt werden; der master sollte außerdem mit einer aktualisierten Versionsnummer getaggt werden.

Durch eine solche dedizierte Entwicklungslinie für Bugfixes kann ein Team Probleme beheben, ohne den Rest des Workflows zu unterbrechen oder auf den nächsten Release-Zyklus warten zu müssen. Maintenance-Branches sind sozusagen Ad-hoc-Release-Branches, die direkt mit dem master interagieren.

Beispiel

Das unten stehende Beispiel zeigt, wie ein einziger Release-Zyklus mit diesem Workflow umgesetzt werden kann. Wir setzen voraus, dass du bereits ein zentrales Repository angelegt hast.

Neuen Branch erstellen

Neuen Branch erstellen

Der erste Schritt ist, den obligatorischen master mit einem develop-Branch zu ergänzen. Entwickler können dies auf einfache Weise bewerkstelligen, indem sie einen leeren develop-Branch lokal erstellen und ihn zum Server pushen:

git branch develop
git push -u origin develop

Dieser Branch wird den kompletten Versionsverlauf des Projekts enthalten, während der master eine verkürzte Version enthält. Andere Entwickler sollten das zentrale Repository nun klonen und einen Tracking-Branch für den develop-Branch erstellen:

git clone ssh://user@host/path/to/repo.git
git checkout -b develop origin/develop

Nun hat jeder eine lokale Kopie der Einrichtung der Verlaufs-Branches.

Mary und John beginnen mit neuen Features

Neue Feature Branches

Unser Beispiel beginnt damit, wie John und Mary an separaten Features arbeiten. Sie müssen beide getrennte Branches für ihre jeweiligen Features erstellen. Anstatt dafür den master als Basis zu verwenden, sollten sie beide ihre feature-Branches auf develop basieren:

git checkout -b some-feature develop

Beide fügen dem Feature Branch auf die übliche Weise neue Commits hinzu: bearbeiten, auf die Staging-Ebene verschieben, committen:

git status
git add <eine-datei>
git commit

Mary schließt ihr Feature ab

Einen Feature Branch mergen

Nachdem sie einige Commits hinzugefügt hat, erklärt Mary ihr Feature für fertig. Wenn ihr Team mit Pull Requests arbeitet, wäre dies ein guter Zeitpunkt, einen zu erstellen und darum zu bitten, ihr Feature in den develop-Branch zu mergen. Andernfalls kann sie es in ihren lokalen develop-Branch mergen und in das zentrale Repository pushen:

git pull origin develop
git checkout develop
git merge ein-feature
git push
git branch -d ein-feature

Der erste Befehl stellt sicher, dass der develop-Branch aktuell ist, bevor versucht wird, das Feature darin zu mergen. Beachte, dass Features niemals direkt in den master gemergt werden sollten. Konflikte werden auf dieselbe Weise wie beim zentralisierten Workflow gelöst.

Mary beginnt mit der Release-Vorbereitung

Release vorbereiten

Während John an seinem Feature weiterarbeitet, beginnt Mary damit, das erste offizielle Release des Projekts vorzubereiten. Sie nutzt wie auch bei der Feature-Entwicklung einen neuen Branch, um die Release-Vorbereitungen zusammenzufassen. In diesem Schritt wird auch die Versionsnummer des Releases festgelegt:

git checkout -b release-0.1 develop

In diesem Branch kannst du das Release bereinigen, umfassend testen, die Dokumentation aktualisieren und weitere Vorbereitungen für das nächste Release treffen. Er ist ähnlich wie ein Feature Branch, der dazu dient, das Release aufzupolieren.

Sobald Mary diesen Branch erstellt und ihn in das zentrale Repository pusht, ist das Release für Features geschlossen. Jede Funktion, die nicht bereits im develop-Branch ist, wird bis zum nächsten Release-Zyklus verschoben.

Mary schließt das Release ab

Release in Master-Branch mergen

Ist das Release bereit zur Auslieferung, mergt Mary es in den master- und den develop-Branch und löscht anschließend den Release-Branch. Es ist wichtig, zurück in den develop-Branch zu mergen, da der Release-Branch eventuell kritische Updates enthalten kann, auf die neue Features Zugriff haben müssen. Und auch hier gilt: Wenn Marys Organisation Code-Reviews nutzt, ist hier ein sehr guter Zeitpunkt für einen Pull Request.

git checkout master
git merge release-0.1
git push
git checkout develop
git merge release-0.1
git push
git branch -d release-0.1

Release-Branches fungieren als Puffer zwischen der Feature-Entwicklung (develop) und öffentlichen Releases (master). Wann immer etwas in den master-Branch gemergt wird, solltest du den Commit taggen, um ihn leicht referenzieren zu können:

git tag -a 0.1 -m "Erstes öffentliches Release" master
git push --tags

Git bringt diverse Hooks mit. Das sind Skripte, die ausgeführt werden, wann immer ein bestimmtes Ereignis im Repository auftritt. Diese Hooks können so konfiguriert werden, dass automatisch ein öffentliches Release erstellt wird, wann immer der master-Branch in das zentrale Repository oder ein Tag gepusht wird.

Endbenutzer entdeckt Bug

Wartungs-Branch

Nach Auslieferung des Release macht sich Mary daran, mit John Features für das nächste Release zu entwickeln. Das geht so lange, bis ein Endnutzer ein Ticket anlegt, in dem er einen Bug im aktuellen Release meldet. Um diesen Bug zu beseitigen, erzeugt Mary (oder John) einen Maintenance-Branch auf Basis des master-Branch, löst das Problem mit so vielen Commits wie erforderlich und mergt den Branch direkt in den master zurück.

git checkout -b issue-#001 master
# Fehler beheben
git checkout master
git merge issue-#001
git push

Wie Release-Branches enthalten auch Maintenance-Branches wichtige Aktualisierungen, die im develop-Branch enthalten sein müssen. Mary muss also auch diesen Merge ausführen. Anschließend kann sie den Branch einfach löschen:

git checkout develop
git merge issue-#001
git push
git branch -d issue-#001

Wie geht es weiter?

Mittlerweile solltest du dich eigentlich mit dem zentralisierten Workflow, dem Feature-Branch-Workflow und dem Gitflow-Workflow ganz gut auskennen. Du solltest auch ein gutes Verständnis für das Potenzial entwickelt haben, das lokale Repositorys, das Push-Pull-Muster und das Branching- und Merging-Modell von Git bieten.

Denk daran, dass die hier vorgestellten Workflows nur mögliche Beispiele sind. Sie stellen keine verbindlichen Regeln für die Git-Nutzung in deiner Arbeitsumgebung auf. Es ist dir also freigestellt, einige Aspekte von Workflows zu übernehmen und andere nicht. Ziel ist es, dass Git deine Arbeitsweise unterstützt, nicht umgekehrt.

Workflows verzweigen

Der Forking-Workflow unterscheidet sich vollkommen von den in diesem Tutorial besprochenen Workflows. Anstatt ein einzelnes serverseitiges Repository als zentrale Codebasis zu verwenden, bietet er jedem Entwickler ein serverseitiges Repository. Jeder Beteiligte arbeitet also nicht mit einem sondern zwei Git-Repositorys: einem privaten, lokalen und einer öffentlichen auf Serverseite.

Git-Workflows: Verzweigungen

Der größte Vorteil des Forking-Workflows ist: Beiträge können integriert werden, ohne dass jeder sie in ein einzelnes zentrales Repository pushen muss. Entwickler pushen stattdessen in ihre eigenen serverseitigen Repositorys und nur der Projekt-Maintainer kann in das offizielle Repository pushen. Dadurch kann dieser Commits von allen möglichen Entwicklern akzeptieren, ohne ihnen Schreibzugriff auf die offizielle Codebasis zu geben.

Als Ergebnis entsteht ein verzweigter Workflow, der großen, organischen Teams (einschließlich nicht vertrauenswürdigen Dritten) Flexibilität zum sicheren Zusammenarbeiten bietet. Damit eignet sich der Workflow auch ideal für Open-Source-Projekte.

Wie es funktioniert

Wie auch andere Git-Workflows basiert der verzweigte Workflow auf einem offiziellen öffentlichen Repository, das auf einem Server gespeichert ist. Wenn jedoch ein neuer Entwickler beginnt, an dem Projekt zu arbeiten, klont er das offizielle Repository nicht direkt.

Stattdessen forken sie das offizielle Repository, um eine Kopie davon auf dem Server zu erstellen. Diese neue Kopie dient als persönliches, öffentliches Repository – keine anderen Entwickler dürfen darauf pushen, sie können aber Änderungen von dort pullen (warum das wichtig ist, sehen wir gleich). Nach der Erstellung der serverseitigen Kopie führt der Entwickler git clone aus, um eine Kopie auf seine lokale Maschine zu ziehen. Diese dient als seine private Entwicklungsumgebung, genau wie in den anderen Workflows.

Ist er bereit, einen lokalen Commit zu veröffentlichen, verschiebt er den Commit in sein eigenes öffentliches Repository – und nicht in das offizielle. Dann sendet er mit dem Haupt-Repository einen Pull Request und die für die Projekt-Wartung zuständige Person weiß, dass eine Aktualisierung zur Integration bereitsteht. Der Pull Request dient auch als praktischer Diskussions-Thread, wenn Issues mit Codebeiträgen auftreten.

Um das Feature in die offizielle Codebasis zu integrieren, pullt der Maintainer die Änderungen des Beteiligten in das eigene lokale Repository; prüft, ob sie sich fehlerfrei in das Projekt integrieren lassen; mergt sie in seinen lokalen master-Branch und pusht den master-Branch dann in das offizielle Repository auf dem Server. Der Beitrag ist nun Bestandteil des Projekts und andere Entwickler sollten diesen Projektstand vom offiziellen Repository pullen, um ihre lokalen Repositorys zu synchronisieren.

Offizielles Repository

Es ist wichtig zu verstehen, dass die Vorstellung eines "offiziellen" Repositorys im verteilten Workflow reine Festlegungssache ist. Aus technischer Sicht besteht für Git kein Unterschied zwischen den öffentlichen Repositorys der einzelnen Entwickler und dem offiziellen Repository. Das offizielle Repository ist einfach deshalb das offizielle, weil es das offizielle Repository der für die Projektwartung zuständigen Person ist.

Branching in verteilten Workflows

All diese persönlichen öffentlichen Repositorys sind einfach eine praktische Methode, um Branches mit anderen Entwicklern zu teilen. Alle sollten Branches nutzen, um individuelle Features zu isolieren – genau wie im Feature-Branch- und im Gitflow-Workflow. Der Unterschied besteht darin, wie die Branches geteilt werden. Während sie in den feature-Branch- und Gitflow-Workflows in das offizielle Repository gepusht werden, sieht der Forking-Workflow vor, dass sie in die lokalen Repositorys anderer Entwickler gepusht werden.

Beispiel

Der Projektwartende legt das offizielle Repository an

Verzweigter Workflow: Gemeinsam genutztes Repository

Wie auch bei einem Git-basierten Projekt wird zunächst auf einem Server ein offizielles Repository erstellt, auf das alle Teammitglieder Zugriff haben. Normalerweise dient dieses Repository auch als öffentliches Repository für den Projektwartenden.

Öffentliche Repositorys sollten immer "bare" sein, und zwar unabhängig davon, ob sie eine offizielle Codebasis darstellen oder nicht. Der Projekt-Maintainer sollte etwa den folgenden Befehl ausführen, um das offizielle Repository einzurichten:

ssh user@host
git init --bare /path/to/repo.git

Bitbucket bietet außerdem als Alternative zu den obigen Befehlen eine praktische GUI. Der Prozess ist dabei identisch mit der Einrichtung eines zentralen Repositorys für die Workflows in diesem Tutorial. Der Wartende sollte die vorhandene Codebasis wenn nötig auch in dieses Repository verschieben.

Entwickler verzweigen das offizielle Repository

Verzweigter Workflow: Offizielles Repository verzweigen

Als Nächstes müssen alle Entwickler dieses offizielle Repository forken. Das ist möglich, indem sie sich per SSH am Server anmelden und git clone ausführen, um das Repository an eine andere Stelle auf dem Server zu kopieren. Richtig, Forking ist im Grunde genommen ein serverseitiger Klon. Bitbucket und Stash erlauben Entwicklern auch hier, ein Repository durch Klicken auf eine Schaltfläche zu forken.

Anschließend sollte jeder Entwickler sein eigenes serverseitiges Repository haben. Wie auch das offizielle Repository sollten alle Bare-Repositorys sein.

Entwickler klonen ihre verteilten Repositorys

Verzweigter Workflow: Verteilte Repositorys klonen

Als Nächstes müssen alle Entwickler ihre eigenen öffentlichen Repository klonen. Das geschieht über den bekannten git clone-Befehl.

Bei unserem Beispiel gehen wir davon aus, dass zum Hosten dieser Repositorys Bitbucket eingesetzt wird. Vergiss nicht, dass jeder Entwickler in diesem Szenario sein eigenes Bitbucket-Account benötigt. Alle sollten ihr serverseitiges Repository mit folgendem Befehl klonen:

git clone https://user@bitbucket.org/user/repo.git

Während die anderen Workflows in diesem Tutorial eine einzelne origin-Remote-Verbindung nutzen, die zum zentralen Repository verweist, erfordert der Forking-Workflow zwei Remote-Verbindungen – eine für das offizielle Repository und eine für das persönliche serverseitige Repository des Entwicklers. Zwar kannst du diese Remote-Verbindungen nennen wie du willst, es ist aber üblich, origin als Remote-Verbindung für dein geforktes Repository zu verwenden (dieses wird automatisch erstellt, wenn du git clone ausführst) und upstream für das offizielle Repository.

git remote add upstream https://bitbucket.org/maintainer/repo

Das Upstream-Remote-Repository musst du mit dem obigen Befehl selbst erstellen. So kannst du dein lokales Repository jederzeit unkompliziert mit den Fortschritten aus dem offiziellen Projekt aktuell halten. Wenn für dein Upstream-Repository Authentifizierung aktiviert ist, es also kein Open-Source-Repository ist, musst du wie folgt einen Benutzernamen angeben:

git remote add upstream https://user@bitbucket.org/maintainer/repo.git

Benutzer müssen dabei vor dem Klonen oder Verschieben aus einer offiziellen Codebasis ein gültiges Passwort angeben.

Entwickler arbeiten an ihren Features

Verzweigter Workflow: Entwickler arbeiten an Features

In den lokalen Repositorys, die sie gerade geklont haben, können Entwickler Code bearbeiten, Änderungen committen und Branches erstellen wie sie es in den anderen Workflows auch getan haben:

git checkout -b ein-feature
# Code bearbeiten
git commit -a -m "Ersten Entwurf eines Features hinzufügen"

Alle ihre Änderungen sind privat, bis sie diese in ihre öffentlichen Repositorys pushen. Wenn das offizielle Projekt fortgeschritten ist, können sie mit git pull auf neue Commits zugreifen:

git pull upstream master

Da Entwickler in einem dedizierten feature-Branch arbeiten sollten, sollte dies zu einem Fast-Forward-Merge führen.

Entwickler veröffentlichen ihre Features

Verzweigter Workflow: Entwickler veröffentlichen Features

Sobald ein Entwickler bereit ist, sein neues Feature zu teilen, stehen zwei Schritte an. Erstens muss er seinen Beitrag den anderen Entwicklern zugänglich machen, indem er ihn in sein öffentliches Repository pusht. Die origin-Remote-Verbindung sollte bereits eingerichtet sein, deshalb genügt der folgende Befehl:

git push origin feature-branch

Dies unterscheidet sich insofern von den anderen Workflows, dass die origin-Remote-Verbindung auf das persönliche serverseitige Repository des Entwicklers verweist und nicht auf die Haupt-Codebasis.

Zweitens muss der Projekt-Maintainer informiert werden, dass das neue Feature in die offizielle Codebasis gemergt werden kann. Bitbucket bietet eine Pull Request-Schaltfläche, die zu einem Formular führt, in dem der Entwickler spezifizieren kann, welcher Branch gemergt werden soll. Normalerweise geht es darum, den feature-Branch in den master-Branch der Upstream-Remote-Verbindung zu integrieren.

Projekt-Wartender integriert Features

Verzweigter Workflow: Features integrieren

Wenn der Projektwartende einen Pull Request erhält, liegt es an ihm zu bestimmen, ob er das Feature in die offizielle Codebasis integriert oder nicht. Dazu muss er sich für eine von zwei Möglichkeiten entscheiden.

  1. Code direkt im Pull Request prüfen

  2. Code direkt in sein lokales Repository verschieben und ihn manuell mergen

Die erste Option ist einfacher, da der Projekt-Maintainer eine Diff-Ansicht der Änderungen zur Verfügung hat, sie kommentieren und über eine grafische Benutzeroberfläche mergen kann. Allerdings muss die zweite Option gewählt werden, wenn der Pull Request einen Merge-Konflikt auslöst. In diesem Fall holt der Maintainer den feature-Branch mit fetch vom serverseitigen Repository des Entwicklers, mergt ihn in seinen lokalen master-Branch und löst die Konflikte auf:

git fetch https://bitbucket.org/user/repo feature-branch
# Änderungen prüfen
git checkout master
git merge FETCH_HEAD

Sind die Änderungen in den lokalen master-Branch integriert, muss der Maintainer ihn in das offizielle Repository auf dem Server pushen, sodass andere Entwickler Zugriff darauf erhalten:

git push origin master

Denke daran, dass origin beim Maintainer auf dessen öffentliches Repository verweist, das auch als offizielle Codebasis des Projekts dient. Der Beitrag des Entwicklers ist nun voll in das Projekt integriert.

Entwickler synchronisieren mit dem offiziellen Repository

Verzweigter Workflow: Mit offiziellem Repository synchronisieren

Da die Haupt-Codebasis weiterverschoben wurde, sollten die Entwickler die Synchronisierung mit dem offiziellen Repository durchführen:

git pull upstream master

Wie geht es weiter?

Falls du über einen SVN-Background verfügst, mag der Forking-Workflow wie ein radikaler Paradigmenwechsel wirken. Doch im Grunde fügt dieser Prozess dem Feature-Branch-Workflow nur eine weitere Abstraktionsebene hinzu. Statt Branches direkt über ein einzelnes zentrales Repository zu teilen, werden Beiträge auf einem serverseitigen Repository veröffentlicht, die den einzelnen Entwicklern gehören.

In diesem Artikel wird beschrieben, wie ein Beitrag von einem Entwickler in den offiziellen master-Branch gelangt. Doch dieselbe Methode kann genutzt werden, um einen Beitrag in jedes beliebige Repository zu integrieren. Wenn ein Teil deines Teams beispielsweise zusammen an einem bestimmten Feature arbeitet, kann es Änderungen auf exakt dieselbe Weise im Team teilen – ohne das Haupt-Repository zu tangieren.

Dadurch ist der verzweigte Workflow ein sehr leistungsstarkes Tool für locker zusammengeschlossene Teams. Jeder Entwickler kann ganz einfach mit anderen Entwicklern Änderungen teilen und jeder Branch kann effizient in die offizielle Codebasis gemergt werden.

Du möchtest mit Git arbeiten?

Sieh dir dieses interaktive Tutorial an.

Get started now