Der perfekte "Git flow" mit GitLab

Welche Entscheidungen wir zur effizienteren Arbeit mit Gitlab getroffen haben.

Ronny Vedrilla
Ronny Vedrilla
, 03. Sep 2020

Einführende Worte

Das Prinzip "Git flow" ist heutzutage vermutlich jedem Entwickler hinlänglich bekannt. Auch wir arbeiten seit Jahren tagtäglich damit. Obwohl die Art der Benennung und der Zusammenführung von Branches einfach genug ist, fällt auf, dass man bei der Nutzung von Git(lab) doch immer wieder Entscheidungen treffen muss. In diesem Artikel gehe ich auf einige ein, die wir getroffen haben und verliere ein Wort darüber, warum wir Dinge tun, wie wir sie tun.

Wir nutzen intern Gitlab - allerdings sollten die meisten Aspekte auch auf GitHub übertragbar sein.

Einen Merge-Request, bitte!

Möchte man einen Branch in einen anderen überführen, empfiehlt es sich, einen Merge-Request (MR) zu erstellen. Das verhindert nicht nur, Fehler beim manuellen Merge zu machen, sondern bietet auch die Möglichkeit der Qualitätskontrolle. Einerseits kann der aktuelle Code durch die Continuous-Integration-Pipeline laufen. Dies ermöglicht bspw. Linting oder Unittesting des Codes. Andererseits kann der Code von einem anderen Entwickler im sogenannten Code Review überprüft werden. In vielen Firmen ist das Code Review ein verpflichtender Teil des Entwicklungsprozesses - zurecht, finden sich doch hierbei oft Bugs, Unschönheiten oder vergessene Grenzfälle, die sonst womöglich erst in Produktion aufgefallen wären.

Beim Branching fängt es an

Das oben beschriebene Konzept ist einfach, allerdings hat man bei der Erstellung diverse Freiheitsgrade. Wir nutzen als Kanban-Board für unsere Tickets die Integration von Gitlab - "Gitlab Issues". Dies ist nützlich, da automatisch Verlinkungen zwischen Code und Ticket erzeugt werden. Schreibt man bspw. die Ticket-ID mit führendem Hashtag in den Titel des Merge-Requests, wird sowohl im MR als auch im Ticket nachgehalten, dass die beiden zusammengehören.

gitlab_requests.jpg

Auf der Abbildung sieht man im Ticket direkt, ob alle Codeänderungen für diese Aufgabe schon erledigt sind.

Erstellt man einen neuen Branch und erstellt erste Commits, so erkennt dies Gitlab und bietet die Möglichkeit, mit einem Klick einen MR zu eröffnen. Enthält der Branchname die Ticket-ID, wird diese automatisch in den Titel geschrieben. Deshalb halte ich Branch-Namen in dieser Form für sinnvoll, da manuelle Fehler verhindert werden:

feature/#27-my-awesome-feature

WIP or not WIP – that is the question

Gitlab bietet die Möglichkeit, noch nicht fertige MRs als "WIP" (Work-in-progress) zu kennzeichnen. Dafür gibt es im Bearbeiten-Modus ein praktisches Feature (zum Hinzufügen oder Entfernen):

gitlab_screenshot.png

Dies dient nicht nur der Übersichtlichkeit, sondern verhindert auch einen versehentlichen Merge über die Benutzeroberfläche.

Eine Markierung von "fertigen" Branches, bspw. mit einem "REVIEW"-Präfix, halte ich persönlich für redundant. Per Definition ist alles, was nicht "WIP" ist, bereit. Warum der extra Aufwand und eine neue potentielle Fehlerquelle einbauen?

Hätten Sie noch eine Konfiguration?

Es gibt darüber hinaus noch zwei Einstellungsmöglichkeiten bei einem Merge Request. "Delete source branch when merge request is accepted." und "Squash commits when merge request is accepted."

Nach dem Merge den Source-Branch zu löschen halte ich in fast allen Fällen für sehr sinnvoll, da ansonsten irgendwann eine endlose Zahl von Branches existiert und niemand mehr sagen kann, welche davon relevante Inhalte enthalten. Natürlich gibt es Fälle, wo es sinnvoll ist, den Branch zu behalten - aber wie man weiß, bestätigen Ausnahmen die Regel.

Praktischerweise kann man diese Einstellung standardmäßig in den Projekteinstellungen aktivieren:

Settings → General → Merge requests → "Enable 'Delete source branch' option by default"

Ich bin neuerdings ebenfalls ein Fan davon, Commits beim Merge zusammenzuführen. Voraussetzung ist, dass von dem aktuellen Branch nicht weiter abgezweigt wurde und dass nur genau eine Person hieran gearbeitet hat. Squashing bedeutet, dass alle Änderungen dieses Branches als ein einziger Commit ohne Änderungshistorie innerhalb des Branches im Zielbranch landen. Der Nachteil ist offensichtlich: Hat jemand sehr kleinteilige und gut dokumentierte Commits erstellt, gehen diese Informationen verloren. Auf der anderen Seite enden mit Squashing fast nur komplette Features und Bugfixes im Dev- bzw. Masterbranch. Gibt es ein Problem auf einem System ist es somit recht einfach herauszufinden, welcher Commit der Übeltäter ist. Dazu kommt, dass viele Entwickler eher knappe Commit-Messages schreiben. Da stellt für mich ein einzelner Commit mit allen Änderungen und ggf. einer umfangreicheren Beschreibung den größeren Mehrwert da.

TL;DR

  1. Merge Requests (MR) nutzen
  2. Gitlabs "WIP"-Prefix im MR-Titel verwenden
  3. Falls Gitlab issues verwendet wird
    1. Branch-Namen mit Ticket-ID und Hashtag ("feature/#27-my-awesome-feature")
    2. Ticket-ID mit führendem Hashtag in MR-Titel verwenden
  4. "Delete source branch"-Option in den Projektsettings aktivieren
  5. Bei der MR-Erstellung "Squash commits" aktivieren, wenn nur eine Person an dem MR gearbeitet hat und keine Kind-Branches existieren