Git Branching mit dem richtigen flow

Git arbeitet mit Branches fast mühelos – Operationen wie checkout und merge werden nahezu verzugslos ausgeführt und durch den 3-Wege-‘merge’, ist häufiges Zusammenführen von Branches, auch über einen längeren Zeitraum, einfach zu bewerkstelligen. Das macht es komfortabel, Workflows zu etablieren, die einem bei der Entwicklung unterstützen.
Auf der NETWAYS Development-Klausur im Februar 2013, haben wir uns dazu entschieden, dem von Vincent Driessen im Jahr 2010 vorgestellten Branching-Modell zu folgen. Für die Umsetzung dieses Modells stellt er Git-Erweiterung, names git-flow bereit.
Dieser Workflow verfolgt den Ansatz, im master-Branch nur Code zu halten, der entweder released wurde oder production ready ist. Parallel dazu, gibt es einen Branch zum Arbeiten, der alle abgeschlossenen Änderungen für das nächste Release enthält. Vincent nennt diesen Zweig develop, wir next. Von diesem Branch würden Nightly Builds erstellt werden. Sobald dieser parallele Zweig einen stabilen Status erreicht, wird er mit dem master zusammengeführt. Erinnern wir uns, dass der master nur Code hält, der released wurde, so wird jedes mal, wenn Änderungen in den master übernommen werden, eine neue Version der Software veröffentlicht.
Neben diesen langfristigen Branches mit unbegrenzter Lebensdauer, werden eine Vielzahl von anderen Zweigen eingesetzt, die paralleles und themenbezogenes Arbeiten, Release-Vorbereitung und Fehlerbehebung von bereits veröffentlichen Versionen erleichtern. Dabei gelten strikte Regeln, bezüglich Namensgebung und von welchem Branch sie sich abzweigen und mit welchem sie zusammengeführt werden. Feature- oder Topic-, Release- und Hotfix-Branches haben eine begrenze Lebensdauer, da sie schlussendlich gelöscht werden.
git-flow_branching
Feature-Branches
In Feature- oder Topic-Branches werden neue Features für zukünftige Releases entwickelt. Welches Release das Feature enthält, muss zum Zeitpunkt der Entwicklung nicht bekannt sein. Der Feature-Branch existiert nur solange, wie das Feature in Entwicklung ist, d.h. bis es zusammengeführt oder verworfen wird. Natürlich können und sollen mehrere Features parallel entwickelt werden.
Ein neuer Feature-Branch zweigt sich vom next ab:

git checkout -b feature/scheduler next

Vorausgesetzt das Feature wird nicht verworfen, wird es für das nächste Release mit next zusammengeführt:

git checkout next
git merge --no-ff feature/scheduler
git branch -d feature/scheduler
git push origin next

Der –no-ff-Schalter (no fast forward) ist ganz wichtig und bewirkt, dass bei einem merge, immer ein neuer commit erzeugt wird. Dadurch geht die historische Existenz eines Feature-Branch nicht verloren und es ist leichter nachzuvollziehen welche commits zu welchem Feature gehör(t)en.
Release-Branches
Release-Branches unterstützen die Vorbereitung eines neuen Release. Ein Release-Branch wird erstellt, wenn next dem gewünschten Zustand des nächsten Release entspricht. Das ist z.B. ab dem Beginn der Testphase oder dem Zeitpunkt des Code-Freeze.
Ab jetzt landen nur noch Bugfixes und Änderungen an Metadaten im Branch. Ein commit der immer gemacht wird, ist die Änderung der Versionsnummer.
Alle Features, die mit in das Release sollen, müssen mit next zusammengeführt worden sein. Features für zukünftige Releases, sind noch nicht im next.
Der Release-Branch zweigt sich vom next ab:

git checkout -b release/1.0 next

Wenn der Branch bereit für ein Release ist, wird er mit dem master zusammengeführt und mit einem tag versehen. Damit in zukünftigen Releases, die hier eingeflossenen Bugfixes nicht fehlen, werden die Änderungen auch in next übernommen:

git checkout master
git merge --no-ff release/1.0
git tag -a 1.0
git checkout next
git merge --no-ff release/1.0
git branch -d release/1.0
git checkout master
git push origin master
git push --tags

Hotfix-Branches
Hotfix-Branches verhalten sich im Grunde wie Release-Branches, allerdings sind diese natürlich ungeplant. Ist das letzte Release fehlerhaft, wird eine neue bereinigte Version der Software veröffentlicht.
Der Hotfix-Branch zweigt sich vom master ab:

git checkout -b hotfix/1.0.1 master

Der oder die Fehler werden jetzt in einem oder mehreren commits behoben. Die Änderung der Versionsnummer darf hier nicht vergessen werden. Wenn der Branch bereit für ein Release ist, wird er mit dem master zusammengeführt und mit einem tag versehen. Damit in zukünftigen Releases, die hier eingeflossenen Bugfixes nicht fehlen, werden die Änderungen auch in next übernommen:

git checkout master
git merge --no-ff hotfix/1.0.1
git tag -a 1.0.1
git checkout next
git merge --no-ff hotfix/1.0.1
git branch -d hotfix/1.0.1
git checkout master
git push origin master
git push --tags

Und wo bleibt der flow?
Alle genannten Operationen werden von den Git-Erweiterungen git-flow bereitgestellt. Um git-flow zu verwenden, muss das repository entsprechend initialisiert werden:

git flow init

Die Operationen für ein neues Release sind mit git-flow deutlich übersichtlicher:

git flow release start 1.0
...
git flow release finish 1.0

Die Befehle für Feature- und Hotfix-Branches sind ähnlich. Nachlesen kann man sie hier. Bis jetzt fahren wir damit ganz gut ;-).
(Bildquelle: entwickler.com)

Eric Lippmann
Eric Lippmann
Lead Senior Developer

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er sich für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.