Git-Workflow für SaaS-Teams: Branching, Releases und Hotfixes in nachhaltigem Tempo

#git workflow für saas teams
Sandor Farkas - Founder & Lead Developer at Wolf-Tech

Sandor Farkas

Gründer & Lead Developer

Experte für Softwareentwicklung und Legacy-Code-Optimierung

Frag fünf Entwickler, wie man branchen sollte, und du bekommst fünf selbstbewusste Antworten und mindestens einen Streit. Diskussionen über Git-Workflows haben etwas Religiöses, was seltsam ist, denn für die meisten Unternehmen ist die richtige Antwort ziemlich langweilig. Dieser Beitrag beschreibt einen Git-Workflow für SaaS-Teams mit etwa 3 bis 15 Entwicklern, also der Größe, bei der wir die meiste Verwirrung sehen. Er ist bewusst meinungsstark. Du kannst einzelnen Entscheidungen widersprechen, aber die Grundform hat sich in jeder SaaS-Codebasis bewährt, an der wir gearbeitet haben.

Die Kurzfassung: Trunk-based Development mit Feature-Branches, die weniger als zwei Tage leben, Feature Flags für alles Unfertige, ein wöchentliches getaggtes Release und Hotfixes, die vom letzten Release-Tag abzweigen. Alles Weitere in diesem Beitrag ist Detail.

Warum langlebige Branches Teams dieser Größe schaden

Der klassische Fehlerfall sieht so aus: Ein Entwickler startet einen Feature-Branch für ein großes Stück Arbeit. Zwei Wochen später hat der Branch 60 Commits, main ist weitergezogen, und der Merge produziert Konflikte in Dateien, die der Entwickler nie angefasst hat. Das Review ist unlesbar, weil es dreitausend Zeilen umfasst. QA testet den Branch und testet ihn nach dem Merge noch einmal, weil der Merge selbst das Verhalten verändert hat. Deployments werden um den großen Merge herum geplant. Alle haben ein bisschen Angst.

Das eigentliche Problem ist die Batch-Größe, Git ist nur der Ort, an dem der Schmerz sichtbar wird. Merge-Konflikte wachsen ungefähr mit dem Quadrat der Branch-Lebensdauer, weil sowohl der Branch als auch main Änderungen ansammeln, die kollidieren können. Halte Branches unter zwei Tagen und Konflikte verschwinden weitgehend. Reviews schrumpfen auf eine Größe, die ein Kollege tatsächlich vor dem Mittagessen lesen kann. Und weil jeder Merge klein ist, dauert es Minuten statt eines Nachmittags voller Bisecting, den Commit zu finden, der etwas kaputt gemacht hat.

GitFlow mit seinem develop-Branch, Release-Branches und Zeremonie wurde für Boxed Software mit parallel unterstützten Versionen entworfen. Ein SaaS-Produkt hat genau eine Version in Produktion. Du brauchst diese Maschinerie nicht.

Der Git-Workflow für SaaS-Teams, den wir empfehlen

Hier ist das gesamte Modell:

  1. Branche von main ab, benannt nach dem Ticket, zum Beispiel feat/1234-invoice-export.
  2. Halte den Branch weniger als zwei Tage am Leben. Ist die Arbeit größer, teile sie auf und verstecke die unfertigen Teile hinter einem Flag.
  3. Öffne einen Pull Request. CI führt das komplette Gate aus: Linting, statische Analyse, Tests. Ein grünes Gate plus ein genehmigendes Review sind die Voraussetzung für den Merge.
  4. Merge nach main. Das deployt automatisch nach Staging, jedes Mal, ohne manuellen Schritt.
  5. Einmal pro Woche wird ein Release geschnitten: main wird getaggt, und der Tag deployt nach Produktion.

Das ist der komplette Happy Path. Es gibt keinen develop-Branch und auch keine Merge-Fenster. Der wöchentliche Rhythmus ist ein Startpunkt, kein Gesetz. Teams, die sich wohlfühlen, gehen oft zu zwei Releases pro Woche oder zu einem Release pro Merge über. Wichtig ist, dass ein Release ein Tag und eine Pipeline ist, kein Meeting.

Ein praktischer Hinweis zu Merges: Squash-merge den PR. Ein Branch wird zu einem Commit auf main, was die Historie lesbar hält und das Cherry-Picking eines einzelnen Fixes trivial macht. Es bedeutet auch, dass der PR-Titel zur Commit-Message wird, was für die Changelog-Automatisierung weiter unten wichtig ist.

Feature Flags statt langer Branches

Der naheliegende Einwand gegen Zwei-Tage-Branches ist, dass echte Features länger als zwei Tage dauern. Stimmt. Die Antwort ist, unfertige Arbeit hinter einem Feature Flag zu mergen, statt sie auf einem Branch altern zu lassen.

Ein Flag muss kein Vendor-Produkt sein. Ein Konfigurationswert oder ein datenbankgestützter Toggle, der an einer Stelle geprüft wird, reicht für den Anfang:

if ($featureFlags->enabled('invoice_export', $account)) {
    // neuer Pfad, gemergt aber dunkel
}

Das verändert, wofür ein Branch da ist. Ein Branch ist nicht mehr der Ort, an dem ein Feature lebt, bis es fertig ist, sondern das Vehikel für die nächste reviewbare Scheibe. Das Feature selbst sammelt sich auf main, dunkel, bis du es einschaltest. Du bekommst Continuous Integration im wörtlichen Sinne, plus einen Rollout-Mechanismus und einen Kill Switch gratis dazu.

Flags haben Hygienekosten. Jedes Flag ist eine Verzweigung in deinem Code, und veraltete Flags verrotten. Lege am Tag, an dem ein Flag ausgeliefert wird, ein Ticket zum Entfernen ins Backlog, und lösche das Flag, sobald das Feature vollständig live ist. Eine Codebasis mit vierzig vergessenen Flags ist ein eigenes Legacy-Problem, und wir haben das bei Code-Audits mehr als einmal gesehen.

Der wöchentliche Release-Cut

Einmal pro Woche, zu einer festen Zeit, über die niemand nachdenken muss, taggt jemand main:

git tag -a v2026.08.27 -m "Release 2026-08-27"
git push origin v2026.08.27

Der Tag löst das Produktions-Deployment aus. Calendar Versioning passt hier besser zu SaaS als Semver, weil deine Kunden keine Versionsnummern konsumieren und ein Datum dir sofort sagt, wie alt ein Release ist.

Warum wöchentlich und nicht bei jedem Merge? Rein als Zwischenschritt. Teams, die von monatlichen oder unregelmäßigen Releases kommen, finden wöchentliche Releases ein angenehmes erstes Ziel: häufig genug, dass jedes Release klein ist, selten genug, dass das Team Vertrauen in die Pipeline aufbauen kann. Staging hat die ganze Woche jeden Merge bekommen, sodass der Release-Kandidat zum Zeitpunkt des Cuts effektiv seit Tagen getestet ist. Wenn der wöchentliche Cut zum Non-Event wird, ist es leicht, den Zyklus zu verkürzen.

Hotfixes ohne Heldentaten

Produktion bricht am Mittwoch. Der Release-Tag vom Dienstag ist v2026.08.26, aber main enthält bereits drei gemergte Features, die du nicht unter Druck ausliefern willst. Das ist das eine Szenario, in dem ein Branch von etwas anderem als main richtig ist:

git checkout -b hotfix/payment-timeout v2026.08.26
# fixen, committen, PR gegen den Branch des Tags, CI läuft
git tag -a v2026.08.26-hotfix.1
git push origin v2026.08.26-hotfix.1

Der Hotfix-Tag deployt nach Produktion. Dann, und diesen Schritt vergessen Teams, cherry-picke den Fix zurück nach main:

git checkout main
git cherry-pick <hotfix-commit-sha>

Lässt du den Cherry-Pick aus, macht das reguläre Release nächste Woche deinen Fix stillschweigend rückgängig. Wenn du eine Sache aus diesem Abschnitt mitnimmst: Mach den Cherry-Pick zum Teil der schriftlichen Hotfix-Prozedur, nicht zu etwas, woran sich der Bereitschaftsentwickler um 23 Uhr erinnern muss.

Release Notes aus Conventional Commits

Handgeschriebene Changelogs sind immer zu spät und meistens falsch. Die Lösung ist, die Information in die Commit-Messages zu legen und ein Tool sie zusammensetzen zu lassen. Conventional Commits liefern das Format: feat: add invoice CSV export, fix: handle payment provider timeout, wobei feat!: Breaking Changes markiert. Da Squash-Merges PR-Titel zu Commit-Messages machen, reicht es, das Format auf PR-Titeln durchzusetzen.

Ein commit-msg-Hook hält das Format lokal ehrlich:

#!/bin/sh
# .git/hooks/commit-msg
pattern='^(feat|fix|chore|docs|refactor|test|perf)(\(.+\))?!?: .+'
if ! head -1 "$1" | grep -qE "$pattern"; then
  echo "Commit message must follow conventional commits, e.g. 'feat: add export'"
  exit 1
fi

Führe dieselbe Prüfung in CI mit commitlint aus, damit der Hook eine Bequemlichkeit ist und nicht die einzige Verteidigungslinie. Zum Release-Zeitpunkt verwandelt ein Changelog-Generator wie git-cliff oder release-please die Commits seit dem letzten Tag in gruppierte Release Notes. Niemand schreibt sie, und sie sind nie veraltet.

Branch Protection, die den Workflow ohne Bürokratie durchsetzt

Der Workflow funktioniert nur, wenn er an einem schlechten Tag nicht umgangen werden kann. Auf GitHub schützt du main mit genau diesen Regeln: Pull Request mit einem genehmigenden Review erforderlich, CI-Statuschecks müssen bestehen, Branches müssen vor dem Merge aktuell sein, Force Pushes und Löschungen sind blockiert. Wende die Regeln auch auf Administratoren an, denn die Person, die unter Druck am ehesten direkt auf main pusht, ist der Gründer.

Widerstehe der Versuchung, mehr hinzuzufügen. Zwei erforderliche Reviewer, verpflichtendes Review durch Code Owner auf jedem Pfad und Merge Queues haben in größeren Organisationen ihren Platz, aber bei 3 bis 15 Entwicklern erzeugt jede zusätzliche Regel vor allem Wartezeit. Füge eine Regel erst hinzu, nachdem ihr Fehlen einen echten Vorfall verursacht hat.

Die GitHub-Actions-Pipeline

Hier ist eine kondensierte Version der Pipeline, die das gesamte Modell ausführt, für ein PHP-Backend, passe die Schritte an deinen Stack an:

name: ci
on:
  pull_request:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: composer install --no-progress
      - run: vendor/bin/php-cs-fixer check
      - run: vendor/bin/phpstan analyse
      - run: vendor/bin/phpunit

  deploy-staging:
    needs: gate
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./bin/deploy staging

  deploy-production:
    needs: gate
    if: startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./bin/deploy production

Die Zeile environment: production gibt dir einen Audit-Trail der Produktions-Deployments und optional ein manuelles Freigabe-Gate, falls deine Compliance-Situation eines verlangt. Die Struktur ist der Punkt: ein Gate-Job, den jeder Pfad teilt, Staging gespeist von main, Produktion gespeist von Tags.

Wo Teams tatsächlich hängen bleiben

Unserer Erfahrung nach ist die Git-Mechanik der einfache Teil. Der schwere Teil ist die Disziplin drumherum: Arbeit klein genug für Zwei-Tage-Branches zu schneiden, Flags genug zu vertrauen, um unfertigen Code zu mergen, und Flags danach aufzuräumen. Das sind Gewohnheiten, und Gewohnheiten brauchen ein paar Monate, um sich zu setzen.

Wenn dein Team irgendwo in diesem Übergang steckt oder dein aktueller Workflow zu etwas gewachsen ist, das niemand erklären kann, können wir helfen. Wir prüfen Branching-, CI- und Release-Setups im Rahmen unseres Code-Quality-Consultings, und wir bauen Delivery-Pipelines wie die oben für Kunden im Rahmen von Custom-Software-Development-Projekten. Schreib an hello@wolf-tech.io oder besuche wolf-tech.io, um zu sehen, wie wir arbeiten.