Ein Git-Workflow ist ein Rezept oder eine Empfehlung für die Verwendung von Git, um Arbeiten auf konsistente und produktive Weise zu erledigen. Git-Workflows ermutigen Benutzer, Git effektiv und konsistent zu nutzen. Git bietet eine große Flexibilität bei der Art und Weise, wie Benutzer Änderungen verwalten. Da der Schwerpunkt von Git auf Flexibilität liegt, gibt es keinen standardisierten Prozess für die Interaktion mit Git. Wenn Sie mit einem Team an einem mit Git verwalteten Projekt arbeiten, müssen Sie sicherstellen, dass sich das Team darüber einig ist, wie der Änderungsfluss angewendet werden soll. Um sicherzustellen, dass das Team auf derselben Seite steht, sollte ein vereinbarter Git-Workflow entwickelt oder ausgewählt werden. Es gibt mehrere veröffentlichte Git-Workflows, die für Ihr Team geeignet sein könnten. Hier werden einige dieser Workflow-Optionen besprochen.
Die Vielzahl möglicher Workflows kann es schwierig machen, zu wissen, wo man bei der Implementierung von Git am Arbeitsplatz beginnen soll. Diese Seite bietet einen Ausgangspunkt, indem sie einen Überblick über die gängigsten Git-Workflows für Software-Teams gibt.
Bei der Lektüre sollten Sie bedenken, dass diese Workflows als Richtlinien und nicht als konkrete Regeln gedacht sind. Wir wollen Ihnen zeigen, was möglich ist, damit Sie Aspekte aus verschiedenen Workflows mischen und anpassen können, um Ihren individuellen Bedürfnissen gerecht zu werden.
Was ist ein erfolgreicher Git-Workflow?
Bei der Evaluierung eines Workflows für Ihr Team ist es am wichtigsten, dass Sie die Kultur Ihres Teams berücksichtigen. Sie möchten, dass der Workflow die Effektivität Ihres Teams steigert und nicht zu einer Belastung wird, die die Produktivität einschränkt. Einige Dinge, die Sie bei der Bewertung eines Git-Workflows berücksichtigen sollten, sind:
- Kann dieser Workflow mit der Teamgröße skaliert werden?
- Ist es einfach, Fehler mit diesem Workflow rückgängig zu machen?
- Bürdet dieser Workflow dem Team einen neuen, unnötigen kognitiven Aufwand auf?
Zentralisierter Workflow
Der zentralisierte Workflow ist ein hervorragender Git-Workflow für Teams, die von SVN umsteigen. Wie Subversion verwendet der Centralized Workflow ein zentrales Repository, das als zentraler Einstiegspunkt für alle Änderungen am Projekt dient. Anstelle von trunk
heißt der Standardentwicklungszweig master
und alle Änderungen werden in diesen Zweig übertragen. Dieser Arbeitsablauf benötigt keine anderen Zweige außer master
.
Die Umstellung auf ein verteiltes Versionskontrollsystem mag wie eine gewaltige Aufgabe erscheinen, aber Sie müssen Ihren bestehenden Arbeitsablauf nicht ändern, um die Vorteile von Git zu nutzen. Ihr Team kann Projekte genau so entwickeln wie mit Subversion.
Die Verwendung von Git für Ihren Entwicklungs-Workflow bietet jedoch einige Vorteile gegenüber SVN. Erstens gibt es jedem Entwickler seine eigene lokale Kopie des gesamten Projekts. Diese isolierte Umgebung ermöglicht es jedem Entwickler, unabhängig von allen anderen Änderungen am Projekt zu arbeiten – er kann Commits zu seinem lokalen Repository hinzufügen und die Upstream-Entwicklungen komplett vergessen, bis es ihm passt.
Zweitens erhalten Sie Zugriff auf das robuste Branching- und Merging-Modell von Git. Anders als SVN sind Git-Zweige als ausfallsicherer Mechanismus für die Integration von Code und den Austausch von Änderungen zwischen Repositories konzipiert. Der zentralisierte Workflow ähnelt anderen Workflows, da er ein entferntes, serverseitig gehostetes Repository verwendet, aus dem Entwickler Push- und Pull-Befehle ausführen. Im Vergleich zu anderen Workflows hat der zentralisierte Workflow keine definierten Pull-Request- oder Forking-Muster. Ein zentralisierter Workflow eignet sich im Allgemeinen besser für Teams, die von SVN auf Git umsteigen, und für kleinere Teams.
Wie es funktioniert
Entwickler beginnen mit dem Klonen des zentralen Repositorys. In ihren eigenen lokalen Kopien des Projekts bearbeiten sie Dateien und nehmen Änderungen vor, wie sie es mit SVN tun würden; allerdings werden diese neuen Übertragungen lokal gespeichert – sie sind komplett vom zentralen Repository isoliert. Dies ermöglicht es den Entwicklern, die Synchronisation nach oben zu verschieben, bis sie an einem geeigneten Haltepunkt sind.
Um Änderungen im offiziellen Projekt zu veröffentlichen, „pushen“ die Entwickler ihren lokalen master
Zweig in das zentrale Repository. Dies ist das Äquivalent von svn commit
, außer dass es alle lokalen Commits hinzufügt, die nicht bereits im zentralen master
Zweig sind.
Initialisieren des zentralen Repository
Zunächst muss jemand das zentrale Repository auf einem Server anlegen. Wenn es sich um ein neues Projekt handelt, können Sie ein leeres Repository initialisieren. Andernfalls müssen Sie ein vorhandenes Git- oder SVN-Repository importieren.
Zentrale Repositories sollten immer Bare Repositories sein (sie sollten kein Arbeitsverzeichnis haben), die wie folgt angelegt werden können:
ssh user@host git init --bare /path/to/repo.git
Stellen Sie sicher, dass Sie einen gültigen SSH-Benutzernamen für user
verwenden, die Domain oder IP-Adresse Ihres Servers für host
, und den Ort, an dem Sie Ihr Repository speichern möchten für /path/to/repo.git
. Beachten Sie, dass die .git
-Erweiterung üblicherweise an den Repository-Namen angehängt wird, um anzuzeigen, dass es sich um ein Bare Repository handelt.
Gehostete zentrale Repositories
Zentrale Repositories werden oft über Git-Hosting-Dienste von Drittanbietern wie Bitbucket Cloud oder Bitbucket Server erstellt. Der oben beschriebene Prozess der Initialisierung eines bloßen Repositorys wird vom Hosting-Dienst für Sie übernommen. Der Hosting-Dienst stellt dann eine Adresse für das zentrale Repository bereit, auf die Sie von Ihrem lokalen Repository aus zugreifen können.
Das zentrale Repository klonen
Als Nächstes erstellt jeder Entwickler eine lokale Kopie des gesamten Projekts. Dies geschieht über den git clone
-Befehl:
git clone ssh://user@host/path/to/repo.git
Wenn Sie ein Repository klonen, fügt Git automatisch eine Verknüpfung mit dem Namen origin
hinzu, die auf das „übergeordnete“ Repository zurückverweist, in der Annahme, dass Sie später mit diesem interagieren möchten.
Änderungen vornehmen und Commit
Wenn das Repository lokal geklont ist, kann ein Entwickler Änderungen mit dem Standard Git Commit Prozess vornehmen: edit, stage, und commit. Falls Sie mit dem Staging-Bereich nicht vertraut sind: Es ist eine Möglichkeit, einen Commit vorzubereiten, ohne jede Änderung in das Arbeitsverzeichnis aufnehmen zu müssen. Dadurch können Sie sehr fokussierte Commits erstellen, auch wenn Sie viele lokale Änderungen gemacht haben.
git status # View the state of the repo git add # Stage a file git commit # Commit a file
Denken Sie daran, dass da diese Befehle lokale Commits erstellen, kann John diesen Prozess so oft wiederholen wie er will, ohne sich darum zu kümmern, was im zentralen Repository passiert. Das kann sehr nützlich für große Funktionen sein, die in einfachere, atomare Teile zerlegt werden müssen.
Neue Commits in das zentrale Repository schieben
Sobald neue Änderungen in das lokale Repository übertragen wurden. Diese Änderungen müssen gepusht werden, um sie mit anderen Entwicklern im Projekt zu teilen.
git push origin master
Dieser Befehl pusht die neuen Änderungen in das zentrale Repository. Beim Pushen von Änderungen in das zentrale Repository ist es möglich, dass zuvor Aktualisierungen von einem anderen Entwickler gepusht wurden, die Code enthalten, der mit den beabsichtigten Push-Aktualisierungen in Konflikt steht. Git gibt dann eine Meldung aus, die auf diesen Konflikt hinweist. In dieser Situation muss zunächst git pull
ausgeführt werden. Dieses Konfliktszenario wird im folgenden Abschnitt näher erläutert.
Konflikte verwalten
Das zentrale Repository repräsentiert das offizielle Projekt, daher sollte seine Commit-Historie als heilig und unveränderlich behandelt werden. Wenn die lokalen Commits eines Entwicklers vom zentralen Repository abweichen, weigert sich Git, seine Änderungen zu pushen, da dies die offiziellen Commits überschreiben würde.
Bevor der Entwickler sein Feature veröffentlichen kann, muss er die aktualisierten zentralen Commits abrufen und seine Änderungen darauf neu basieren. Das ist so, als würde man sagen: „Ich möchte meine Änderungen zu dem hinzufügen, was alle anderen bereits gemacht haben.“ Das Ergebnis ist eine perfekt lineare Historie, genau wie in traditionellen SVN-Workflows.
Wenn lokale Änderungen direkt mit Upstream-Commits in Konflikt stehen, hält Git den Rebase-Prozess an und gibt Ihnen die Möglichkeit, die Konflikte manuell zu lösen. Das Schöne an Git ist, dass es die gleichen git status
und git add
Befehle sowohl für die Erzeugung von Commits als auch für die Auflösung von Merge-Konflikten verwendet. Das macht es für neue Entwickler einfach, ihre eigenen Merges zu verwalten. Und wenn sie in Schwierigkeiten geraten, macht es Git sehr einfach, den gesamten Rebase abzubrechen und es noch einmal zu versuchen (oder Hilfe zu suchen).
Beispiel
Lassen Sie uns ein allgemeines Beispiel nehmen, wie ein typisches kleines Team mit diesem Workflow zusammenarbeiten würde. Wir werden sehen, wie zwei Entwickler, John und Mary, an getrennten Funktionen arbeiten und ihre Beiträge über ein zentrales Repository austauschen können.
John arbeitet an seiner Funktion
In seinem lokalen Repository kann John Features mit dem Standard-Git-Commit-Prozess entwickeln: edit, stage und commit.
Da diese Befehle lokale Commits erzeugen, kann John diesen Prozess beliebig oft wiederholen, ohne sich Gedanken darüber zu machen, was im zentralen Repository vor sich geht.
Mary arbeitet an ihrem Feature
In der Zwischenzeit arbeitet Mary an ihrem eigenen Feature in ihrem eigenen lokalen Repository und verwendet dabei denselben Edit/Stage/Commit-Prozess. Wie John kümmert sie sich nicht darum, was im zentralen Repository vor sich geht, und es ist ihr wirklich egal, was John in seinem lokalen Repository tut, da alle lokalen Repositorys privat sind.
John veröffentlicht sein Feature
Wenn John sein Feature fertiggestellt hat, sollte er seine lokalen Commits im zentralen Repository veröffentlichen, damit andere Teammitglieder darauf zugreifen können. Er kann dies mit dem Befehl git push
wie folgt tun:
git push origin master
Erinnern Sie sich, dass origin
die Remote-Verbindung zum zentralen Repository ist, die Git erstellt hat, als John es klonte. Das Argument master
weist Git an, zu versuchen, den origin
-Zweig des master
so aussehen zu lassen wie seinen lokalen master
-Zweig. Da das zentrale Repository nicht mehr aktualisiert wurde, seit John es geklont hat, wird dies zu keinen Konflikten führen und der Push wird wie erwartet funktionieren.
Mary versucht, ihr Feature zu veröffentlichen
Lassen Sie uns sehen, was passiert, wenn Mary versucht, ihr Feature zu pushen, nachdem John seine Änderungen erfolgreich im zentralen Repository veröffentlicht hat. Sie kann genau den gleichen Push-Befehl verwenden:
git push origin master
Aber da ihre lokale Historie vom zentralen Repository abweicht, wird Git die Anfrage mit einer ziemlich ausführlichen Fehlermeldung ablehnen:
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.
Damit wird verhindert, dass Mary offizielle Commits überschreibt. Sie muss Johns Aktualisierungen in ihr Repository ziehen, sie mit ihren lokalen Änderungen integrieren und es dann erneut versuchen.
Mary rebasiert auf Johns Commit(s)
Mary kann git pull
verwenden, um Upstream-Änderungen in ihr Repository einzubinden. Dieser Befehl ist eine Art svn update
– er zieht die gesamte Upstream-Commit-Historie in Marys lokales Repository und versucht, sie in ihre lokalen Commits zu integrieren:
git pull --rebase origin master
Die --rebase
-Option weist Git an, alle Commits von Mary an die Spitze des master
-Zweigs zu verschieben, nachdem sie mit den Änderungen aus dem zentralen Repository synchronisiert wurden, wie unten gezeigt:
Der Pull würde immer noch funktionieren, wenn Sie diese Option vergessen, aber Sie würden jedes Mal mit einem überflüssigen „Merge Commit“ enden, wenn jemand mit dem zentralen Repository synchronisieren muss. Für diesen Arbeitsablauf ist es immer besser, ein Rebase zu machen, anstatt einen Merge-Commit zu erzeugen.
Mary löst einen Merge-Konflikt auf
Rebasing funktioniert, indem jeder lokale Commit einzeln in den aktualisierten master
-Zweig übertragen wird. Das bedeutet, dass Sie Merge-Konflikte auf einer Commit-zu-Commit-Basis abfangen, anstatt sie alle in einem massiven Merge-Commit aufzulösen. Das hält Ihre Commits so fokussiert wie möglich und sorgt für eine saubere Projekthistorie. Das wiederum macht es viel einfacher, herauszufinden, wo Fehler eingeführt wurden und, falls nötig, Änderungen mit minimalen Auswirkungen auf das Projekt zurückzunehmen.
Wenn Mary und John an nicht verwandten Funktionen arbeiten, ist es unwahrscheinlich, dass der Rebasing-Prozess Konflikte erzeugt. Falls doch, hält Git das Rebase beim aktuellen Commit an und gibt die folgende Meldung zusammen mit einigen relevanten Anweisungen aus:
CONFLICT (content): Merge conflict in
Das Tolle an Git ist, dass jeder seine eigenen Merge-Konflikte auflösen kann. In unserem Beispiel würde Maria einfach ein git status
ausführen, um zu sehen, wo das Problem liegt. Die konfliktbehafteten Dateien werden im Abschnitt Unmerged Pfade angezeigt:
# Unmerged paths: # (use "git reset HEAD ..." to unstage) # (use "git add/rm ..." as appropriate to mark resolution) # # both modified:
Dann wird sie die Datei(en) nach ihrem Geschmack bearbeiten. Wenn sie mit dem Ergebnis zufrieden ist, kann sie die Datei(en) auf die übliche Weise bereitstellen und git rebase
den Rest erledigen lassen:
git add git rebase --continue
Und das war’s auch schon. Git geht zum nächsten Commit über und wiederholt den Vorgang für alle anderen Commits, die Konflikte erzeugen.
Wenn Sie an diesem Punkt ankommen und merken, dass Sie keine Ahnung haben, was los ist, geraten Sie nicht in Panik. Führen Sie einfach den folgenden Befehl aus und Sie sind wieder da, wo Sie angefangen haben:
git rebase --abort
Maria veröffentlicht erfolgreich ihr Feature
Nachdem sie die Synchronisation mit dem zentralen Repository abgeschlossen hat, kann Mary ihre Änderungen erfolgreich veröffentlichen:
git push origin master
Wo geht es weiter
Wie Sie sehen, ist es möglich, eine traditionelle Subversion-Entwicklungsumgebung mit nur einer Handvoll Git-Befehlen zu replizieren. Das ist großartig für den Übergang von Teams von SVN, aber es nutzt nicht die verteilte Natur von Git.
Der zentralisierte Workflow ist großartig für kleine Teams. Der oben beschriebene Konfliktlösungsprozess kann einen Engpass bilden, wenn Ihr Team größer wird. Wenn Ihr Team mit dem Centralized Workflow zufrieden ist, aber die Zusammenarbeit optimieren möchte, lohnt es sich, die Vorteile des Feature Branch Workflows zu erkunden. Indem jedem Feature ein isolierter Zweig gewidmet wird, ist es möglich, eingehende Diskussionen über neue Ergänzungen zu initiieren, bevor sie in das offizielle Projekt integriert werden.
Andere gängige Workflows
Der Centralized Workflow ist im Wesentlichen ein Baustein für andere Git-Workflows. Die meisten gängigen Git-Workflows haben eine Art zentrales Repo, aus dem die einzelnen Entwickler Push- und Pull-Befehle ausführen. Im Folgenden werden einige andere beliebte Git-Workflows kurz erläutert. Diese erweiterten Workflows bieten speziellere Muster in Bezug auf die Verwaltung von Zweigen für die Feature-Entwicklung, Hotfixes und die letztendliche Veröffentlichung.
Feature Branching
Feature Branching ist eine logische Erweiterung des zentralisierten Workflows. Die Kernidee hinter dem Feature Branch Workflow ist, dass die gesamte Feature-Entwicklung in einem dedizierten Zweig statt im master
-Zweig stattfinden soll. Diese Kapselung macht es für mehrere Entwickler einfach, an einem bestimmten Feature zu arbeiten, ohne die Haupt-Codebasis zu stören. Es bedeutet auch, dass der master
Zweig niemals fehlerhaften Code enthalten sollte, was ein großer Vorteil für kontinuierliche Integrationsumgebungen ist.
Gitflow-Workflow
Der Gitflow-Workflow wurde erstmals 2010 in einem viel beachteten Blogbeitrag von Vincent Driessen bei nvie veröffentlicht. Der Gitflow Workflow definiert ein striktes Verzweigungsmodell, das sich an der Projektveröffentlichung orientiert. Dieser Workflow fügt keine neuen Konzepte oder Befehle hinzu, die über das hinausgehen, was für den Feature Branch Workflow erforderlich ist. Stattdessen weist er den verschiedenen Zweigen ganz bestimmte Rollen zu und definiert, wie und wann sie interagieren sollen.
Forking Workflow
Der Forking Workflow unterscheidet sich grundlegend von den anderen in diesem Tutorial besprochenen Workflows. Anstatt ein einziges serverseitiges Repository zu verwenden, das als „zentrale“ Codebasis fungiert, gibt er jedem Entwickler ein serverseitiges Repository. Das bedeutet, dass jeder Mitwirkende nicht nur ein, sondern zwei Git-Repositorys hat: ein privates lokales und ein öffentliches serverseitiges.
Richtlinien
Es gibt keine Einheitsgröße für den Git-Workflow. Wie bereits erwähnt, ist es wichtig, einen Git-Workflow zu entwickeln, der eine Produktivitätssteigerung für Ihr Team darstellt. Neben der Teamkultur sollte ein Workflow auch die Unternehmenskultur ergänzen. Git-Funktionen wie Zweige und Tags sollten den Veröffentlichungszeitplan Ihres Unternehmens ergänzen. Wenn Ihr Team eine Projektmanagement-Software zur Aufgabenverfolgung verwendet, sollten Sie Zweige verwenden, die den laufenden Aufgaben entsprechen. Darüber hinaus gibt es einige Richtlinien, die Sie bei der Entscheidung für einen Workflow berücksichtigen sollten:
Kurzlebige Zweige
Je länger ein Zweig getrennt vom Produktionszweig lebt, desto höher ist das Risiko für Merge-Konflikte und Herausforderungen bei der Bereitstellung. Kurzlebige Zweige fördern saubere Zusammenführungen und Deployments.
Reverts minimieren und vereinfachen
Es ist wichtig, einen Workflow zu haben, der proaktiv hilft, Zusammenführungen zu verhindern, die rückgängig gemacht werden müssen. Ein Workflow, der einen Zweig testet, bevor er in den master
Zweig zusammengeführt wird, ist ein Beispiel dafür. Allerdings können Unfälle passieren. Aus diesem Grund ist es von Vorteil, einen Workflow zu haben, der einfache Reverts erlaubt, die den Fluss für andere Teammitglieder nicht stören.
Passend zum Release-Plan
Ein Workflow sollte den Release-Zyklus Ihrer Software-Entwicklung ergänzen. Wenn Sie planen, mehrmals am Tag zu veröffentlichen, werden Sie Ihren master
-Zweig stabil halten wollen. Wenn Ihr Veröffentlichungszeitplan weniger häufig ist, sollten Sie die Verwendung von Git-Tags in Betracht ziehen, um einen Zweig einer Version zuzuordnen.
Zusammenfassung
In diesem Dokument haben wir Git-Workflows besprochen. Wir haben einen zentralisierten Workflow mit praktischen Beispielen eingehend betrachtet. In Erweiterung des zentralisierten Workflows haben wir weitere spezialisierte Workflows besprochen. Einige wichtige Erkenntnisse aus diesem Dokument sind:
- Es gibt keinen einheitlichen Git-Workflow
- Ein Workflow sollte einfach sein und die Produktivität Ihres Teams steigern
- Ihre geschäftlichen Anforderungen sollten bei der Gestaltung Ihres Git-Workflows helfen
Wenn Sie mehr über den nächsten Git-Workflow erfahren möchten, lesen Sie unsere umfassende Analyse des Feature Branch Workflows.