Eine Branching-Strategie definiert, wie ein Team Branches organisiert, benennt und für verschiedene Zwecke nutzt. Sie ist eine Konvention darüber, welche Branches wann erstellt werden, wer welche Branches nutzt und wie diese Branches in der Entwicklungspipeline zusammenspielen. Im Gegensatz zu technischen Git-Mechanismen, die durch die Software vorgegeben sind, ist eine Branching-Strategie eine organisatorische Entscheidung – eine Vereinbarung im Team über den Workflow.
Git selbst erzwingt keine bestimmte Strategie. Es bietet leichtgewichtige Branches und flexible Mechanismen, aber wie diese genutzt werden, liegt in der Hand des Teams. Ein Zwei-Personen-Projekt kann mit einem einzigen Branch auskommen. Ein hundertköpfiges Team mit parallelen Releases benötigt komplexere Strukturen. Die richtige Strategie hängt von Projektgröße, Release-Frequenz, Team-Struktur und CI/CD-Infrastruktur ab.
Ohne explizite Strategie entsteht Chaos. Entwickler erstellen Branches nach Belieben, Namenskonventionen fehlen, es ist unklar, welcher Branch deployed werden sollte, und Konflikte häufen sich. Eine klare Strategie gibt Struktur:
Klarheit über Verantwortlichkeiten: Welcher Branch repräsentiert Production? Wo werden neue Features entwickelt? Wer darf in welchen Branch commiten?
Vorhersagbare CI/CD-Trigger: Moderne Pipelines
reagieren auf Branch-Events. Eine Strategie definiert: Commits auf
main triggern Production-Deployment, Commits auf
Feature-Branches nur Tests, Tags triggern Releases.
Parallelität ohne Kollisionen: Mehrere Entwickler können gleichzeitig arbeiten, wenn klar ist, wer welchen Branch nutzt und wann Branches zusammengeführt werden.
Release-Management: Wie werden Versionen gebaut? Wie werden Hotfixes deployed? Eine Strategie beantwortet diese Fragen konsistent.
Eine gute Branching-Strategie ist dokumentiert, verstanden und wird gelebt. Sie ist nicht in Stein gemeißelt – Teams passen sie an, wenn sich Anforderungen ändern. Aber zu jedem Zeitpunkt sollte klar sein, welche Regeln gelten.
Bevor wir konkrete Strategien betrachten, die grundlegenden Muster, aus denen sie aufgebaut sind:
Long-lived Branches existieren über die gesamte Projektlaufzeit. Sie repräsentieren dauerhafte Zustände – typischerweise Production, Staging oder Development.
Beispiele: - main oder master: Der
produktive Code - develop: Die aktuelle Entwicklungsarbeit
- staging: Code im Staging-Environment
Diese Branches werden nicht gelöscht. Sie wachsen kontinuierlich durch Integration von Änderungen aus anderen Branches. Long-lived Branches sind die Rückgrat-Struktur des Repositories.
Charakteristik: Dauerhaft, geschützt (oft mit Zugriffsregeln), repräsentieren spezifische Environments oder Zustände.
Short-lived Branches werden für spezifische Aufgaben erstellt und nach Abschluss gelöscht. Typischerweise:
Diese Branches haben eine kurze Lebensdauer – Stunden bis Wochen. Nach Fertigstellung werden sie in einen long-lived Branch integriert und gelöscht.
Charakteristik: Temporär, aufgabenspezifisch, werden nach Integration gelöscht.
Release-Branches werden für die Vorbereitung
spezifischer Releases erstellt. Während auf develop
weiterentwickelt wird, stabilisiert sich der Release-Branch: Nur
Bugfixes, keine neuen Features.
Beispiel: Für Version 2.0 wird release/2.0 erstellt. Das
Team fixiert Bugs im Release-Branch, während neue Features für 2.1
bereits auf develop entwickelt werden. Nach dem Release
wird der Release-Branch oft gelöscht oder archiviert.
Charakteristik: Zeitlich begrenzt (für eine Version), nur stabilisierende Änderungen, dienen der Release-Vorbereitung.
Manche Teams nutzen Branches, um Environments zu repräsentieren: -
production: Was auf Production läuft -
staging: Was auf Staging läuft - development:
Was im Development-Environment läuft
Deployments werden durch Änderungen in diesen Branches getriggert.
Ein Commit auf production deployed automatisch in
Production.
Charakteristik: Environment-spezifisch, Deployments durch Branch-Updates getriggert, dauerhaft.
Aus diesen Mustern haben sich standardisierte Strategien entwickelt. Jede hat ihre Philosophie, Stärken und Schwächen.
Git Flow (Vincent Driessen, 2010) ist eine formale, strukturierte Strategie mit klar definierten Branch-Typen und -Regeln.
Branch-Struktur: - main:
Production-Code, jeder Commit ist ein Release - develop:
Integration-Branch für Features - feature/*: Short-lived
Branches für neue Features (aus develop) -
release/*: Vorbereitung neuer Releases (aus
develop) - hotfix/*: Dringende
Production-Fixes (aus main)
gitGraph
commit id: "Initial"
branch develop
commit id: "Dev work"
branch feature/new-feature
commit id: "Feature A"
commit id: "Feature B"
checkout develop
merge feature/new-feature
branch release/1.0
commit id: "RC fixes"
checkout main
merge release/1.0 tag: "v1.0.0"
checkout develop
merge release/1.0
branch hotfix/critical
checkout main
merge hotfix/critical tag: "v1.0.1"
checkout develop
merge hotfix/critical
Workflow: 1. Features werden in
feature/*-Branches entwickelt 2. Fertige Features werden in
develop integriert 3. Für ein Release wird
release/X.Y von develop abgezweigt 4. Der
Release-Branch wird stabilisiert (nur Bugfixes) 5. Der Release wird in
main integriert und getaggt 6. main und
develop bleiben synchron
Hotfix-Flow: Dringende Fixes werden aus
main abgezweigt, gefixxt, in main UND
develop integriert.
Stärken: - Sehr strukturiert, klare Regeln -
Trennung von Production (main) und Development
(develop) - Gut für Projekte mit geplanten Releases -
Parallele Release-Vorbereitung möglich
Schwächen: - Komplex für kleine Teams oder schnelle
Releases - Zwei long-lived Branches (main und
develop) erhöhen Synchronisationsaufwand - Kann zu langen
Feature-Branches führen
Geeignet für: Größere Teams, Software mit Release-Zyklen, Projekte mit Wartungs-Releases (mehrere Versionen parallel).
GitHub Flow reduziert Komplexität radikal. Nur ein
long-lived Branch (main), alles andere sind
Feature-Branches.
Branch-Struktur: - main:
Production-Code, immer deploybar - feature/* oder
fix/*: Short-lived Branches für alles andere
Workflow: 1. Erstelle Feature-Branch von
main 2. Committe Änderungen in Feature-Branch 3. Öffne Pull
Request (Code Review) 4. Nach Approval: Integriere in main
5. main wird automatisch deployed 6. Lösche
Feature-Branch
Kern-Prinzipien: - main ist immer
deploybar - Jede Änderung geht durch einen Feature-Branch - Pull
Requests erzwingen Code Review - Integration bedeutet Deployment
Stärken: - Extrem simpel, leicht zu lernen - Kurze Feedback-Zyklen - Fördert Continuous Deployment - Minimaler Overhead
Schwächen: - Kein explizites Release-Management -
Schwierig bei mehreren parallelen Releases - Erfordert robuste
automatisierte Tests - Nicht geeignet, wenn main nicht
immer deploybar sein kann
Geeignet für: Web-Apps mit Continuous Deployment, kleine bis mittlere Teams, Projekte ohne feste Release-Zyklen.
GitLab Flow ist GitHubs Antwort auf die Lücke zwischen Git Flow und GitHub Flow. Es kombiniert Einfachheit mit Flexibilität für verschiedene Deployment-Szenarien.
Variante 1: Environment Branches
Für Projekte mit mehreren Deployment-Environments:
Branch-Struktur: - main: Entwicklung -
staging: Staging-Environment - production:
Production-Environment
Workflow: 1. Entwickle in Feature-Branches 2.
Integriere in main (deployed zu Dev-Environment) 3. Wenn
stabil: Integriere main in staging 4. Nach
Validierung: Integriere staging in
production
Jede Integration triggert Deployment in entsprechendes Environment.
Variante 2: Release Branches
Für Projekte mit versionierten Releases:
Branch-Struktur: - main: Aktuelle
Entwicklung - 2-3-stable, 2-4-stable:
Maintenance-Branches für Releases
Workflow: 1. Entwickle auf main 2. Für
Release: Tag auf main (z.B. v2.4.0) 3. Falls
Maintenance nötig: Erstelle 2-4-stable-Branch 4. Bugfixes
gehen in Maintenance-Branch, werden zurück zu main
portiert
Stärken: - Flexibel für verschiedene Szenarien - Environment-Branches machen Deployment-Status explizit - Einfacher als Git Flow, strukturierter als GitHub Flow
Schwächen: - Mehrere Varianten können verwirren - Environment-Branches können zu manuellen Integrations-Steps führen
Geeignet für: Projekte mit GitLab CI/CD, Multiple Environments, sowohl Continuous Deployment als auch versioned Releases.
Trunk-Based Development minimiert Branch-Lebensdauer
extrem. Alle Entwickler committen direkt oder über sehr kurzlebige
Branches in einen zentralen “Trunk” (main).
Branch-Struktur: - main (der “Trunk”):
Einziger dauerhafter Branch - Sehr kurzlebige Feature-Branches (Stunden
bis 1-2 Tage) – optional
Workflow: 1. Kleine Änderungen direkt in
main ODER 2. Sehr kurzer Feature-Branch → schnelle
Integration 3. Feature Flags für unfertige Features 4. Releases durch
Tags auf main
Kern-Prinzipien: - Branches leben maximal 1-2 Tage - Integration mindestens täglich - Feature Flags statt lange Branches - Robuste automatisierte Tests essentiell
Stärken: - Minimale Merge-Komplexität - Erzwingt echte Continuous Integration - Schnelles Feedback - Keine lange divergierten Branches
Schwächen: - Erfordert Disziplin und Erfahrung - Feature Flags erhöhen Code-Komplexität - Schwierig für unerfahrene Teams - Benötigt exzellente Test-Coverage
Geeignet für: Erfahrene Teams, High-Frequency Deployment, Web Services, Teams mit starker CI/CD-Kultur.
Moderne CI/CD-Systeme reagieren auf Git-Events. Die Branching-Strategie definiert, welche Events welche Pipeline-Steps triggern.
Typische Muster:
| Branch-Pattern | Triggered Actions | Environment |
|---|---|---|
main |
Build, Test, Deploy | Production |
develop |
Build, Test, Deploy | Development |
staging |
Build, Test, Deploy | Staging |
feature/* |
Build, Test | (keine Deployment) |
release/* |
Build, Test, Deploy | Staging/Pre-Prod |
hotfix/* |
Build, Test, Deploy | (nach Approval) Production |
Beispiel GitLab CI-Konfiguration (konzeptuell):
# Build & Test auf allen Branches
build:
script: npm run build
test:
script: npm test
# Deploy nur auf spezifischen Branches
deploy_production:
script: deploy.sh production
only:
- main
deploy_staging:
script: deploy.sh staging
only:
- staging
- /^release\/.*/
deploy_development:
script: deploy.sh dev
only:
- developViele Teams nutzen Tags für Release-Trigger statt Branches:
main oder developv2.1.0)Vorteile: - Klare Release-Markierung - Branches bleiben simpler - Semantic Versioning durch Tag-Namen
Beispiel:
release:
script: build_and_deploy.sh
only:
- tags
except:
- branchesNur Tags triggern diese Pipeline, nicht Branch-Commits.
Feature-Branches triggern oft spezielle Merge Request Pipelines: - Preview-Deployments - Extended Tests - Code Quality Checks - Security Scans
Diese Pipelines laufen bei jedem Commit im MR, geben kontinuierliches Feedback, verhindern Integration von problematischem Code.
Es gibt keine universell beste Strategie. Die Wahl hängt von mehreren Faktoren ab:
Klein (2-5 Entwickler): GitHub Flow oder Trunk-Based Development. Minimaler Overhead, schnelle Integration.
Mittel (5-20): GitLab Flow oder vereinfachter Git Flow. Etwas mehr Struktur, klare Verantwortlichkeiten.
Groß (20+): Git Flow oder strukturierter GitLab Flow. Formale Regeln nötig, parallele Arbeit an vielen Features.
Continuous (mehrmals täglich): GitHub Flow oder
Trunk-Based. main ist immer Production.
Regelmäßig (wöchentlich/monatlich): GitLab Flow mit Environment-Branches oder GitHub Flow mit Release-Tags.
Geplant (quartalsweise): Git Flow mit Release-Branches. Zeit für Stabilisierung zwischen Releases.
Multiple Versions: Git Flow mit Maintenance-Branches. Support für mehrere Versionen parallel.
Single Environment: GitHub Flow genügt.
main = Production.
Multiple Environments: GitLab Flow mit Environment-Branches. Explizite Promotion zwischen Environments.
On-Premise + Cloud: Git Flow oder GitLab Flow. Verschiedene Branches für verschiedene Deployment-Targets.
Hoch reguliert (Finance, Healthcare): Git Flow. Klare Trennung, Audit-Trail, manuelle Approvals.
Standard: GitLab Flow. Balance zwischen Kontrolle und Geschwindigkeit.
Minimal: GitHub Flow oder Trunk-Based. Schnelligkeit über formale Prozesse.
Junior-lastig: Git Flow oder GitLab Flow. Klare Regeln, schwer falsch zu machen.
Gemischt: GitLab Flow. Flexibel genug, nicht zu komplex.
Senior-lastig: Trunk-Based oder GitHub Flow. Vertrauen auf Team-Kompetenz.
Keine Strategie muss dogmatisch befolgt werden. Teams passen an:
Git Flow Lite: Git Flow ohne
develop-Branch. Features gehen direkt in main,
Release-Branches für Stabilisierung.
GitHub Flow mit Staging: GitHub Flow +
staging-Branch für Pre-Production-Validierung.
Trunk-Based mit Long-Lived Features: Trunk-Based Development, aber lange Features in Branches mit Feature Flags.
Wichtig: Anpassungen müssen dokumentiert und kommuniziert sein. Ein “fast wie GitHub Flow, aber…” ist verwirrend.
Branching-Strategien sind nicht statisch. Sie entwickeln sich mit dem Projekt:
Phase 1 (Early Development): GitHub Flow. Schnell iterieren, wenig Overhead.
Phase 2 (Growth): Übergang zu GitLab Flow. Mehr Entwickler, Environment-Branches für Stabilität.
Phase 3 (Maturity): Eventuell Git Flow. Multiple Releases, Maintenance-Branches, formale Prozesse.
Phase 4 (Optimization): Zurück zu Trunk-Based. Team ist erfahren, Prozesse automatisiert.
Regelmäßige Retrospektiven: Funktioniert unsere Strategie noch? Zu komplex? Zu simpel? Anpassen nach Bedarf.
Unabhängig von der gewählten Strategie, einige universelle Prinzipien:
Dokumentation: Schreibe die Strategie auf. Neue Teammitglieder müssen sie verstehen können.
Branch-Naming: Konsistente Namen.
feature/, bugfix/, hotfix/,
release/ als Präfixe. Include Ticket-Nummer:
feature/JIRA-123-new-login.
Branch-Protection: Long-lived Branches schützen. Keine direkten Commits, nur über Pull Requests. Require Reviews.
Short-Lived Branches: Feature-Branches sollten Tage, nicht Wochen leben. Je länger, desto schwieriger die Integration.
Regelmäßige Integration: Auch in Feature-Branches regelmäßig vom Haupt-Branch pullen. Verhindert große Konflikte.
Clean-Up: Gelöschte Branches aufräumen. Alte Branches verwirren und blähen das Repository.
CI/CD First: Strategie sollte CI/CD-Pipelines optimal nutzen. Branches, die nichts triggern, bringen keinen Wert.
Communication: Große Merges kommunizieren. “Ich merge Feature X in main heute Nachmittag” verhindert Überraschungen.
Zu viele Long-Lived Branches: Mehr als 3-4 dauerhafte Branches werden unübersichtlich.
Sehr lange Feature-Branches: Branches, die Wochen oder Monate leben, führen zu “Integration Hell”.
Inkonsistente Naming: new-feature,
feature_login, FEAT-signup – Chaos.
Direkte Commits auf Production-Branch:
main sollte geschützt sein. Änderungen nur über Merges.
Vergessene Branches: Hunderte alter Feature-Branches, die niemand löscht. Regelmäßig aufräumen.
Überengineering: Git Flow mit 7 Branch-Typen für ein 3-Personen-Team ist Overkill.
Keine Strategie: “Jeder macht, was er will” führt zu Chaos.
Eine Branching-Strategie ist keine technische Notwendigkeit – Git funktioniert mit beliebigen Workflows. Sie ist eine organisatorische Entscheidung, die Klarheit und Effizienz bringt.
Die “beste” Strategie existiert nicht. Git Flow ist nicht “besser” als GitHub Flow – sie sind für unterschiedliche Kontexte optimiert. Die richtige Wahl hängt von Team, Projekt, Release-Prozessen und Tooling ab.
Beginne simpel. Ein neues Projekt kann mit GitHub Flow starten. Wenn Komplexität wächst, passe an. Wechsel zu GitLab Flow oder Git Flow, wenn nötig. Oder bleibe bei GitHub Flow, wenn es funktioniert.
Dokumentiere die Entscheidung. Kommuniziere die Regeln. Leben die Strategie konsequent. Evaluiere regelmäßig. Sei bereit anzupassen.
Am Ende ist die beste Branching-Strategie die, die das Team versteht, befolgt und die die Entwicklung beschleunigt statt bremst. Technische Perfektion ist weniger wichtig als praktische Tauglichkeit.
Branches sind billig, flexibel, mächtig. Die Strategie definiert, wie diese Macht strukturiert genutzt wird. Eine gute Strategie macht Branches zu einem Enabler paralleler, effizienter Entwicklung. Eine schlechte macht sie zur Quelle von Frustration und Konflikten.
Wähle weise, aber dogmatisch. Die Strategie dient dem Team, nicht umgekehrt.