Skip to content

Git Workflow(s) für SmartHomeNG

msinn edited this page Jan 28, 2024 · 6 revisions

Dieser Workflow wurde bis zum Release 1.6.1 genutzt!

Diese Seite beschreibt den für SmartHomeNG verwendeten Workflow für

  • die "normale" Entwicklung
  • die Entwicklung größerer Features (mit Branching)
  • die Erstellung von Releases
  • die Erstellung von Hotfixes

Der hier verwendete Gitflow Workflow ist abgeleitet von A successful Git branching model (Autor: Vincent Driessen)

Weitere Informationen zu Gitflow finden sich auch hier in den Git Tutorials bei Atlassian.

Der graphische Git Client SoureTree von Atlassian unterstützt Gitflow. Ein Blog hierzu findet sich auch bei Atlassian.

Gitflow Überblick

git-flow

Die Haupt-Zweige/Branches

Im Kern ist das Entwicklungsmodell sehr stark von vorhandenen Modellen. Der zentrale Repo hält zwei Branches (Zweige) mit einer unendlichen Lebensdauer:

  • master
  • develop

Der master Branch (origin/master) sollte jedem Git-Benutzer vertraut sein. Parallel zum master Branch existiert ein weiterer Branch namens develop.

Wir betrachten origin/master als Hauptzweig, wo der Quellcode von HEAD immer einen produktionsbereiten Zustand reflektiert.

Wir betrachten den origin/develop den Hauptzweig, wo der Quellcode von HEAD immer einen Zustand mit den zuletzt gelieferten Entwicklungsänderungen für die nächste Version widerspiegelt. Manche nennen dies die "Integration-Branch".

Wenn der Quellcode im develop Branch einen stabilen Punkt erreicht und bereit ist, freigegeben zu werden, sollten alle Änderungen wieder in den Master verschmolzen und dann mit einer Freigabenummer versehen werden. Wie dies im Detail geschehen wird, wird unten erörtert.

Deshalb ist jedes Mal wenn Änderungen wieder in den master gemerged werden, per Definition ein neues Produktions-Release.

Unterstützende Zweige/Branches

Neben den Hauptzweigen master und develop nutzt unser Entwicklungsmodell eine Vielzahl von unterstützenden Branches, um die parallele Entwicklung zwischen den Teammitgliedern zu erleichtern, die Verfolgung von Features zu erleichtern, sich auf Produktionsfreigaben vorzubereiten und bei der schnellen Fehlerbehebung zu helfen. Anders als die Hauptzweige haben diese Zweige immer eine begrenzte Lebensdauer, da sie schließlich entfernt werden.

Die verschiedenen Arten von Zweigen, die wir verwenden können, sind:

Jeder dieser Zweige hat einen bestimmten Zweck und ist an strenge Regeln gebunden, welche Zweige ihre Ursprungszweige sein können und welche Zweige ihre Zusammenführungsziele sein müssen. Wir werden in einer Minute durch die einzelnen Branches gehen.

Keineswegs sind diese Zweige "besonders" aus technischer Sicht. Die Zweigarten werden durch die Art und Weise, wie wir sie verwenden, kategorisiert. Sie sind natürlich normale Git-Zweige.

Feature Branches

git-flow Feature-Branch

Können abzweigen von:

develop

Müssen wieder gemerged werden in:

develop

Branch Namenskonvention:

Alles außer master, develop, release-* oder hotfix-*

Feature-Branches werden verwendet, um neue Features für die bevorstehende oder eine ferne Zukunft Release zu entwickeln. Wenn man die Entwicklung eines Merkmals beginnt, kann das Release, in die diese Funktion eingebaut wird, noch unbekannt sein. Das Wesen eines Feature Branches ist, dass er existiert, solange das Feature in der Entwicklung ist. Er wird aber schließlich wieder in develop gemerged (um das neue Feature der kommenden Veröffentlichung hinzufügen) oder verworfen (im Falle eines enttäuschenden Experiments).

Feature-Zweige existieren häufig nur im Entwickler-Repos, nicht im origin. Es kann jedoch sinnvoll sein, Feature Branches auf github zu pushen, damit Andere die Entwicklung testen und/oder kommentieren können.

Erstellen eines Feature-Branches

Zum Start der Arbeit an einem neuen Feature, erzeuge einen Branch von develop.

Switch to a new branch "myfeature"

$ Git checkout -b myfeature develop

Oder mit SourceTree:

  • mit dem Befehl Branch:

    git-flow merge Feature-Branch

Einen fertigen Feature-Branch in develop integrieren

Fertige Funktionen können in den develop Branch gemerged werden, um sie in die kommende Version zu bringen:

Switch to branch 'develop'

$ git checkout develop

merge feature

$ git merge --no-ff myfeature
   Updating ea1b82a..05e9557
   (Summary of changes)

Delete branch myfeature (was 05e9557).

$ git branch -d myfeature

Push changes to gitgub

$ git push origin develop

Das -no-ff-Flag veranlasst den Merge, immer ein neues Commit-Objekt zu erstellen, auch wenn der Merge mit einem Fast-Forward durchgeführt werden könnte. Dies vermeidet es, Informationen über die historische Existenz eines Feature-Zweigs zu verlieren und gruppiert alle Commits, die zusammen das Feature hinzugefügt haben.

Vergleiche:

git-flow merge Feature-Branch

Im zweiten Fall ist es unmöglich, aus der Git-Geschichte zu sehen, welche der Commit-Objekte zusammen ein Feature implementiert haben - man müsste manuell alle Log-Meldungen lesen. Das Zurücksetzen eines ganzen Merkmals (d.h. eine Gruppe von Commits), ist im zweiten Fall gruselig, während es leicht gemacht wird, wenn das Flag --no-ff verwendet wurde.

Ja, es werden ein paar mehr (leere) Commit-Objekte erstellt, aber der Vorteil überwiegt die Nachteile.

Oder mit SourceTree:

  • den Featurebranch (myfeature) auschecken

  • mit dem Befehl Merge:

    git-flow merge Feature-Branch
  • mit dem Befehl Branch den Featurebranch löschen

    git-flow merge Feature-Branch

Release Branches

Können abzweigen von:

develop

Müssen wieder gemerged werden in:

develop und master

Branch Namenskonvention:

release-*

Relase-Branches unterstützen die Vorbereitung der Freigabe einer neuen Version. Sie erlauben Last-Minute-Fixes. Darüber hinaus erlauben sie die Vorbereitung von Metadaten für eine Freigabe (Versionsnummer, Builddaten usw.). Wenn all diese Arbeit auf einem Release-Zweig gemacht wird, wird der develop Branch frei, um Features für die nächste große Version zu entwickeln.

Der entscheidende Moment, um einen neuen Release-Zweig von der Entwicklung zu verzweigen, ist, wenn er (fast) den gewünschten Zustand der neuen Version reflektiert. Zumindest alle Features, die für das Release vorgesehen sind, müssen zu diesem Zeitpunkt in develop zusammengeführt worden sein. Alle Funktionen, die auf zukünftige Releases ausgerichtet sind, können nicht - sie müssen warten, bis der Release-Zweig abgezweigt ist. Vorher ist eine Entwicklung für zukünftige Releases nur in Feature Branches möglich.

Es ist genau zu Beginn eines Release-Zweigs, dass dem kommenden Release eine Versionsnummer zugewiesen wird - nicht früher. Bis zu diesem Moment spiegelte der Entwicklungszweig Änderungen für die "nächste Version", aber es ist unklar, ob diese "nächste Version" schließlich 0.3 oder 1.0 wird, bis der Release-Zweig gestartet wird. Diese Entscheidung wird zu Beginn des Release-Zweigs getroffen und wird nach den Regeln des Projekts für die Versionsnummerierung durchgeführt.

Erstellen eines Release-Branches

Release Branches werden aus dem develop Branch erstellt. Zum Beispiel, sagen Version 1.2 ist das aktuelle Produktion Release und wir haben ein größeres Release. Der Entwicklungsstand ist bereit für die "nächste Version" und wir haben beschlossen, dass dies Version 1.3 (statt 1.2.6 oder 2.0) werden wird. So zweigen wir einen Release Branch ab und geben dem Release-Zweig einen Namen, der die neue Versionsnummer widerspiegelt:

Switch to a new branch "release-1.3"

$ git checkout -b release-1.3 develop

Modify files to bump version to 1.3.

$ ./bump-version.sh 1.3
$ git commit -a -m "Bumped version number to 1.3"
   [release-1.2 74d9424] Bumped version number to 1.3
   1 files changed, 1 insertions(+), 1 deletions(-)

Oder mit SourceTree:

  • mit dem Befehl Branch:

    git-flow merge Feature-Branch
  • und anschließend dem Befehl Push:

    git-flow merge Feature-Branch

Nach dem Erstellen eines neuen Branches und dem Umschalten darauf ändern (bumpen) wir die Versionsnummer. Dazu ist die Datei bin/shngversion.py anzupassen. Außerdem sind evtl. noch weitere Änderungen notwendig. Es kann sein, dass Dateien entfernt werden müssen, die nicht in das Release übernommen werden sollen. Anschließend werden diese Änderungen und die neue Versionsnummer committed.

Dieser neue Zweig kann für eine Weile existieren, bis das Release endgültig ausgerollt werden kann. Während dieser Zeit können Fehlerkorrekturen in diesem Zweig eingefügt werden (und nicht auf dem Entwicklungszweig). Das Hinzufügen großer neuer Features ist hier streng verboten. Sie müssen in develop gemerged werden und warten daher auf das nächste Release.

Die Fehlerkorrekturen, die im Release Branch eingefügt wurden, werden (gleich oder) später mit einem Merge des Release Branches in den develop Branch überführt.

Einen Release Branch abschließen

Wenn der Zustand des Release-Zweigs bereit ist, ein echtes Release zu werden, müssen einige Aktionen durchgeführt werden. Zuerst wird der Release-Zweig in Master verschmolzen (Jeder Commit auf Master ist per Definition ist eine neue Version). Als nächstes muss dieses Commit auf den master Branch für eine einfache zukünftige Bezugnahme auf diese historische Version markiert (getagged) werden. Schließlich müssen die Änderungen, die auf dem Release-Zweig vorgenommen werden, in die Entwicklung zurückgeführt werden, so dass zukünftige Releases auch diese Bug-Fixes enthalten.

Die ersten beiden Schritte in Git:

Switch to branch 'master'

$ git checkout master

Merge the release branch into 'master'

$ git merge --no-ff release-1.3
    Merge made by recursive.
    (Summary of changes)

Tag the release

$ git tag -a 1.3

Alternativ kann das Tag auf den Commit gebunden werden:

$ git tag 1.3 <commit>

Das Release ist nun fertig und wurde für zukünftige Referenz markiert.

Um die Änderungen die im Release-Branch gemacht wurden zu erhalten, müssen wir diese wieder in die Entwicklung zu bringen.

In Git:

Switched to branch 'develop'

$ git checkout develop
$ git merge --no-ff release-1.3
    Merge made by recursive.
    (Summary of changes)

Dieser Schritt kann zu einem Merge-Konflikt führen (wahrscheinlich sogar, da wir die Versionsnummer geändert haben). Wenn ja, beheben und committen.

Jetzt sind wir wirklich fertig und der Release-Zweig kann entfernt werden, da wir es nicht mehr brauchen:

$ git branch -d release-1.3
    Deleted branch release-1.3 (was ff452fe).

Hotfix Branches

git-flow Feature-Branch

Können abzweigen von:

master

Müssen wieder gemerged werden in:

develop and master

Branch Namenskonvention:

hotfix-*

Hotfix-Branches sind den Release-Branches sehr ähnlich. Auch sie sollen für eine neue Produktionsfreigabe vorbereiten, wenn auch eine ungeplante. Sie ergeben sich aus der Notwendigkeit, sofort auf einen unerwünschten Zustand einer Live-Produktionsversion zu reagieren. Wenn ein kritischer Fehler in einer Produktionsversion sofort aufgelöst werden muss, kann ein Hotfix-Zweig aus dem entsprechenden Tag auf dem Master-Zweig abgezweigt werden, der die Produktionsversion markiert.

Das Essenzielle ist, dass die Arbeit der Teammitglieder (auf dem develop Branch) fortfahren kann, während eine andere Person eine schnelle Produktionsreparatur vorbereitet.

Erstellen eines Hotfix-Branches

Hotfix-Zweige werden aus dem **master Branch erstellt. Zum Beispiel: sagen wir Version 1.3 ist das aktuelle Produktion Release und verursacht Probleme durch einen schweren Bug. Aber Veränderungen in der Entwicklung sind noch nicht stabil. Wir können dann einen Hotfix-Zweig abzweigen und das Problem beheben:

Switch to a new branch "hotfix-1.3.1"

$ git checkout -b hotfix-1.3.1 master

Modify files to bump version to 1.3.1.

$ ./bump-version.sh 1.3.1
$ git commit -a -m "Bumped version number to 1.3.1"
    [hotfix-1.3.1 41e61bb] Bumped version number to 1.3.1
    1 files changed, 1 insertions(+), 1 deletions(-)

Nicht vergessen die Versionsnummer nach dem Branch anzupassen!

Anschließend den Fehler beheben und den Fix in einem oder mehreren separaten Commits mergen.

$ git commit -m "Fixed severe production problem"
    [hotfix-1.3.1 abbe5d6] Fixed severe production problem
    5 files changed, 32 insertions(+), 17 deletions(-)

Einen Hotfix Branch abschließen

Wenn der Fix fertig ist, muss der Bugfix wieder in den master gemerged werden, er muss aber auch in den develop Branch integriert werden, um sicherzustellen, dass der Bugfix auch in der nächsten Version enthalten ist. Dies ist sehr ähnlich wie Release-Branches abgeschlossen werden.

Zuerst den Master aktualisieren und das Release Taggen.

Switch to branch 'master'

$ git checkout master

Merge hotfix into 'master'

$ git merge --no-ff hotfix-1.3.1
    Merge made by recursive.
    (Summary of changes)

Tag 'master'

$ git tag -a 1.3.1

Alternativ kann das Tag auf den Commit gebunden werden:

$ git tag 1.3.1 <commit>

Als nächstes gehört der Bugfix auch in den develop Branch:

Switch to branch 'develop'

$ git checkout develop

Merge hotfix into 'develop'

$ git merge --no-ff hotfix-1.2.1
    Merge made by recursive.
    (Summary of changes)

Die einzige Ausnahme von der Regel hier ist, dass wenn ein Release-Zweig derzeit existiert, die Hotfix-Änderungen in diesen Release-Zweig gemerged werden müssen, anstatt in develop. Das Back-Merging des Bugfixes in den Release-Zweig wird schließlich dazu führen, dass der Bugfix in develop gemerged wird, wenn der Release-Zweig beendet ist. (Wenn die Arbeit in der Entwicklung sofort verlangt dieses Bugfix und kann nicht warten, bis die Release-Zweig beendet werden, kann bereits jetzt der Release Branch mit dem Bugfix in develop gemerged werden.)

Abschließend den Hotfix Branch entfernen:

$ git branch -d hotfix-1.3.1
    Deleted branch hotfix-1.3.1 (was abbe5d6).