Ein praktischer Leitfaden zu Git-Branching-Strategien
Die meisten Teams wählen keine Branching-Strategie – sie erben, was die Gründungsentwickler eben gemacht haben, und es verfestigt sich, bevor jemand fragt, ob es zur tatsächlichen Teamgröße und Release-Frequenz passt. So landet man bei einem Fünf-Personen-Startup mit einem Prozess für eine Hundert-Personen-Organisation mit Quartals-Releases, oder bei einem Team, das täglich in Produktion deployt und trotzdem einen permanenten develop-Branch pflegt, dessen Zweck niemand mehr kennt. Die richtige Strategie hängt ausschließlich davon ab, wie oft du deployst und wie viele Dinge gleichzeitig in Arbeit sind – nicht davon, welche das schönste Diagramm hat.
Trunk-based Development
Alle committen auf main (oder auf sehr kurzlebige Branches, die innerhalb eines Tages gemergt werden), hinter Feature-Flags, wenn die Arbeit für Nutzer noch nicht sichtbar sein soll.
git checkout main
git pull
git checkout -b add-export-button
# ... small, focused change ...
git push -u origin add-export-button
# open PR, merge same day, delete branch
Das funktioniert gut, wenn du häufig deployst – mehrmals täglich oder zumindest täglich – und solide CI sowie Feature-Flags hast. Der Punkt ist, dass Branches nie lange genug leben, um weit von main abzudriften, sodass Merge-Konflikte klein bleiben und Integrationsprobleme sofort auffallen, statt sich aufzustauen. Ohne Feature-Flags fällt es auseinander: Wird aus „kleine, fokussierte Änderung" unbemerkt „halbfertiges Feature, das Nutzer sehen", hat man nur einen langlebigen Branch mit zusätzlichen Schritten neu erfunden.
Git Flow
Das klassische Schwergewicht: ein permanenter develop-Branch zur Integration, feature/-Branches von develop, release/-Branches zum Stabilisieren einer Version und main ausschließlich für das, was tatsächlich in Produktion ist, mit hotfix/*-Branches, um es direkt zu patchen.
git checkout develop
git checkout -b feature/user-avatars
# ... work, potentially over days or weeks ...
git checkout develop
git merge --no-ff feature/user-avatars
# when develop is ready to ship
git checkout -b release/2.4.0 develop
# stabilization fixes go here, then:
git checkout main
git merge --no-ff release/2.4.0
git tag v2.4.0
git checkout develop
git merge --no-ff release/2.4.0
Das ergibt Sinn, wenn du tatsächlich nach Zeitplan auslieferst – eine Desktop-App mit Quartals-Releases, ein Firmware-Update für Embedded-Geräte, alles, wo „was gerade in main ist" und „worauf wir aktiv hinarbeiten" wochenlang verschiedene Dinge sein müssen. Bei einer kontinuierlich deployten Web-App bringt die Trennung in develop/release Zeremonie ohne entsprechenden Nutzen – es gibt keinen eigenen „Release"-Moment, auf den man hin stabilisieren müsste.
GitHub Flow
Der Mittelweg: kein develop, keine release-Branches. main ist immer deploybar, Feature-Branches gehen direkt davon ab, und das Mergen nach main löst ein Deployment aus.
git checkout main
git pull
git checkout -b fix-pagination-off-by-one
# ... work ...
git push -u origin fix-pagination-off-by-one
# open PR, get review, merge — CI deploys main automatically
Das ist der Standard, zu dem viele Teams greifen sollten: die Klarheit von Git Flow (ein echter Branch pro Arbeitseinheit, per PR geprüft) ohne die Buchführung über mehrere Branches, und es passt natürlich zu Continuous Deployment, weil genau ein Branch zählt. Der Kompromiss gegenüber Trunk-based Development ist die Lebensdauer der Branches – ein Feature-Branch kann hier ein paar Tage für Review und Iteration leben, was etwas Merge-Drift zurückbringt, die reines Trunk-based vermeidet, dafür bekommt man aber einen echten Review-Checkpoint, bevor Code main erreicht.
Eine auswählen
- Trunk-based: mehrmals täglich deployen, Feature-Flag-Infrastruktur vorhanden, das Team committet diszipliniert klein.
- GitHub Flow: mindestens ein paar Mal pro Woche deployen, PR-Review als Gate gewünscht, keine parallelen Release-Linien nötig.
- Git Flow: einzelne, nummerierte Releases mit echter Zeit dazwischen, eine ältere Version muss gepatcht werden, während die nächste entsteht.
Die Teamgröße spielt eine kleinere Rolle, als man annimmt. Auch ein Solo-Entwickler profitiert von der PR-pro-Änderung-Disziplin des GitHub Flow als Dokumentation der Absicht, selbst wenn niemand sonst reviewt. Ein Zwanzig-Personen-Team kann Trunk-based Development erfolgreich betreiben, wenn die Investition in CI und Flags da ist – die Grenze ist die Prozessreife, nicht die Kopfzahl.
Namenskonventionen, die wirklich helfen
Welche Strategie du auch wählst: Ein einheitliches Branch-Präfix macht git branch -a und CI-Dashboards auf einen Blick lesbar:
feature/short-description
fix/short-description
chore/short-description
hotfix/short-description
Verzichte darauf, Ticketnummern als einzige Kennung zu verwenden (JIRA-4521) – in sechs Monaten weiß niemand mehr, was das war, ohne nachzuschlagen, während fix/export-csv-encoding sofort Bescheid gibt. Wenn dein Tracker für die Automatisierung wichtig ist, setze die Ticket-ID hinter die Beschreibung, nicht an ihre Stelle: fix/export-csv-encoding-JIRA-4521.
Die eine Gewohnheit, die wichtiger ist als die Strategie
Unabhängig vom Modell: Merge oder rebase vom Basis-Branch, bevor du einen PR öffnest, nicht erst, wenn Review-Kommentare zu einem inzwischen veralteten Diff eintrudeln.
git checkout feature/add-export-button
git fetch origin
git rebase origin/main
# resolve conflicts here, while the change is fresh in your head
git push --force-with-lease
--force-with-lease statt --force ist hier wichtig – es weigert sich, den Remote-Branch zu überschreiben, wenn jemand anderes seit deinem letzten Fetch darauf gepusht hat, was ein einfaches --force stillschweigend überschreiben würde.
Fazit
Es gibt keine universell richtige Branching-Strategie – nur die, die zu deiner tatsächlichen Deploy-Frequenz passt. Trunk-based und GitHub Flow gehen beide davon aus, dass main fast immer auslieferbar ist, und unterscheiden sich vor allem darin, wie viel Review-Reibung vor einem Merge liegt; Git Flow nimmt an, dass es das nicht ist, und bezahlt dafür mit mehr Branches, die man im Blick behalten muss. Wähle danach, wie oft du auslieferst, nicht danach, welches Diagramm im Wiki am raffiniertesten aussieht.