Stabile Releases von Code Freeze bis Deployment
Wer Releases direkt von main oder develop ausliefert, riskiert instabile Versionen und blockierte Feature-Entwicklung. Strukturierte Release-Branches trennen Stabilisierung von neuer Entwicklung, semantische Versionierung macht Änderungen nachvollziehbar, signierte Tags schaffen vertrauenswuerdige Auslieferungspunkte, Cherry-Pick-Backporting bringt Bugfixes sicher in aeltere unterstuetzte Versionen und CI/CD-Pipelines reagieren automatisch und kontrolliert auf Branches und Tags.
Inhaltsverzeichnis
- 1. Was Release-Branches sind und warum Stabilisierung zaehlt
- 2. Release-Branch erstellen: Code Freeze aus develop
- 3. Semantic Versioning: MAJOR.MINOR.PATCH richtig waehlen
- 4. Releases taggen: annotierte und signierte Git-Tags
- 5. Backporting: Bugfixes per Cherry-Pick zurueckportieren
- 6. Mehrere Release-Branches parallel pflegen
- 7. Release-Branches mit CI/CD-Pipelines koordinieren
- 8. Merge-back: Release-Branch zurueck nach main/develop
- 9. Release-Branches im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Was Release-Branches sind und warum Stabilisierung zaehlt
Ein Release-Branch ist ein eigener Git-Branch, der ausschließlich für die Stabilisierung einer bevorstehenden Version existiert, getrennt von der laufenden Feature-Entwicklung auf main oder develop. Sobald ein Release-Branch existiert, duerfen dort nur noch Bugfixes, Dokumentation und Release-Vorbereitung einfliessen, keine neuen Features mehr. Das trennt zwei Anliegen, die in einem einzigen Branch kollidieren wuerden: die Frage, ob eine Version stabil genug für Kunden ist, und die Frage, was als Naechstes entwickelt wird.
Ohne diese Trennung entsteht ein bekanntes Muster: Ein Team baut kurz vor dem geplanten Release-Termin noch ein Feature ein, ein Merge bricht die Testsuite, und der Release verschiebt sich um Tage. Ein Release-Branch verhindert das, weil Feature-Arbeit ungestoert auf main oder develop weiterlaeuft, während der Release-Branch nur noch schrumpft, nie waechst. Fuer Magento-Projekte mit mehreren gleichzeitig betreuten Kundenumgebungen ist das besonders wertvoll, weil sich Hotfixes gezielt gegen einen konkreten, eingefrorenen Stand entwickeln lassen statt gegen einen sich staendig aendernden Hauptbranch.
2. Release-Branch erstellen: Code Freeze aus develop
Der Release-Branch entsteht am Code-Freeze-Datum, dem Zeitpunkt, an dem der Funktionsumfang der Version feststeht. Ueblich ist die Namenskonvention release/2.5.0, abgezweigt von develop mit git checkout -b release/2.5.0 develop. Ab diesem Moment werden neue Features ausschließlich weiter gegen develop entwickelt, während der Release-Branch nur noch Fixes erhaelt, die die Freigabe der Version nicht gefaehrden.
Direkt nach der Erstellung lohnt sich ein Versions-Bump-Commit, der Versionsnummern in composer.json oder einer VERSION-Datei aktualisiert, damit Build-Artefakte von Anfang an korrekt beschriftet sind. Ab hier greift meist ein Vier-Augen-Prinzip für Merges in den Release-Branch: Jeder Fix durchlaeuft Review und automatisierte Tests, bevor er in die Stabilisierungsphase einfliesst, weil jede Aenderung das Risiko für den bevorstehenden Release-Termin erhoeht.
#!/usr/bin/env bash
# Create a release branch at code freeze from develop
set -euo pipefail
git checkout develop
git pull origin develop
# Branch name convention: release/MAJOR.MINOR.PATCH
git checkout -b release/2.5.0 develop
# Bump version in project files
sed -i 's/"version": ".*"/"version": "2.5.0"/' composer.json
git add composer.json
git commit -m "chore(release): bump version to 2.5.0"
git push -u origin release/2.5.0
3. Semantic Versioning: MAJOR.MINOR.PATCH richtig waehlen
Semantic Versioning strukturiert Versionsnummern als MAJOR.MINOR.PATCH, wobei jede Stelle eine klare Bedeutung traegt. MAJOR steigt bei inkompatiblen Änderungen, die bestehenden Code brechen können. MINOR steigt bei neuen, abwaertskompatiblen Funktionen. PATCH steigt bei abwaertskompatiblen Bugfixes ohne neue Funktionalitaet. Diese Konvention gibt Konsumenten einer Bibliothek oder eines Moduls sofort Auskunft darueber, wie riskant ein Update ist, ohne den Changelog lesen zu müssen.
Die Entscheidung über den Versionssprung sollte nicht subjektiv getroffen werden, sondern anhand einer festen Checkliste: Wurde eine oeffentliche Methode entfernt oder ihre Signatur geaendert, ist es MAJOR. Wurde ein neues Feature additiv ergaenzt, ist es MINOR. Wurde nur ein Bug behoben, ist es PATCH. Pre-Release-Kennungen wie 2.5.0-rc.1 oder 2.5.0-beta.2 markieren Zwischenstaende, die noch nicht als stabil gelten, und Build-Metadaten wie 2.5.0+build.42 dokumentieren zusaetzliche Build-Informationen, ohne die Versionsvorrangregeln zu beeinflussen.
4. Releases taggen: annotierte und signierte Git-Tags
Ein Git-Tag markiert einen unveraenderlichen Punkt in der Historie als Release. Annotierte Tags, erzeugt mit git tag -a v2.5.0 -m "Release 2.5.0", speichern Tagger, Datum und Nachricht als eigenes Objekt in der Git-Datenbank und sind damit klar von leichten Tags zu unterscheiden, die nur ein Zeiger auf einen Commit sind. Fuer Releases sollten ausschließlich annotierte Tags verwendet werden, weil sie in git describe und Release-Tools korrekt als vollwertige Objekte erscheinen.
Signierte Tags erhoehen die Vertrauenswuerdigkeit zusaetzlich: git tag -s v2.5.0 -m "Release 2.5.0" signiert den Tag mit dem GPG-Schluessel des Releasers, und git tag -v v2.5.0 verifiziert die Signatur spaeter gegen den oeffentlichen Schluessel. Fuer regulierte Umgebungen oder Projekte mit vielen Committern belegt eine gueltige Signatur, dass ein Release tatsaechlich von einer autorisierten Person stammt und nicht nachtraeglich manipuliert wurde. Tags werden separat gepusht mit git push origin v2.5.0, da git push Tags standardmaessig nicht automatisch mitschickt.
# Create an annotated tag for the release
git checkout release/2.5.0
git tag -a v2.5.0 -m "Release 2.5.0: stabilization complete"
# Sign the tag with your GPG key (recommended for production releases)
git tag -s v2.5.0 -m "Release 2.5.0: stabilization complete"
# Verify a signed tag before deploying
git tag -v v2.5.0
# Tags are not pushed automatically, push explicitly
git push origin v2.5.0
# List all release tags in semver order
git tag --list "v*" --sort=-v:refname
5. Backporting: Bugfixes per Cherry-Pick zurueckportieren
Backporting bedeutet, einen Bugfix, der zuerst auf main oder develop entwickelt wurde, gezielt in einen aelteren, noch unterstuetzten Release-Branch zu uebertragen. Das Standardwerkzeug dafuer ist git cherry-pick, das einen einzelnen Commit als eigenstaendige Aenderung auf einen anderen Branch anwendet, ohne die komplette Historie dazwischen mitzunehmen. Das ist essenziell, wenn ein Kunde noch auf Version 2.4.x laeuft, der Fix aber zuerst gegen die aktuelle Entwicklungslinie geschrieben wurde.
In der Praxis empfiehlt sich git cherry-pick -x, weil das Flag die urspruengliche Commit-ID in der neuen Commit-Message referenziert und damit Nachvollziehbarkeit über Branches hinweg schafft. Konflikte beim Cherry-Pick sind normal, wenn sich der Code seit dem Fix strukturell veraendert hat, und werden wie ein normaler Merge-Konflikt aufgeloest, bevor git cherry-pick --continue den Vorgang abschliesst. Fuer mehrere betroffene Branches lohnt sich ein kleines Skript, das den Cherry-Pick nacheinander auf jeden Ziel-Branch anwendet und fehlschlagende Branches klar meldet, statt still abzubrechen.
# Backport a bugfix commit from develop to an older release branch
git checkout release/2.4.x
git pull origin release/2.4.x
# -x appends "(cherry picked from commit <sha>)" for traceability
git cherry-pick -x 8f3a1c2
# Resolve conflicts manually, then continue
git status
git add src/app/code/Mironsoft/Checkout/Model/QuoteValidator.php
git cherry-pick --continue
git push origin release/2.4.x
6. Mehrere Release-Branches parallel pflegen
Groessere Projekte pflegen haeufig mehrere Release-Branches parallel, etwa 2.4.x für Bestandskunden und 2.5.x für die aktuelle Version, jeweils mit eigener Support-Zusage. Eine klare Support-Matrix, die festlegt, wie lange welche Linie noch Sicherheitsfixes erhaelt, verhindert Missverstaendnisse darueber, wohin ein Fix ueberhaupt gehoert. Ohne diese Matrix landen Fixes zufaellig nur in dem Branch, den der Entwickler gerade offen hat, und aeltere Kunden bleiben unversorgt.
Um den Ueberblick zu behalten, hilft ein Changelog-Eintrag pro Branch und eine Konvention, jeden Backport-Commit mit der Zielversion zu kennzeichnen. Manche Teams automatisieren das mit Bots, die bei einem gemergten Pull-Request auf main automatisch Backport-Pull-Requests gegen alle aktiv unterstuetzten Release-Branches oeffnen, sodass Cherry-Picks nicht manuell nachgezogen werden müssen. Wichtig bleibt trotzdem ein manueller Review-Schritt, weil ein automatischer Cherry-Pick bei stark abweichendem Code leise falsche Ergebnisse produzieren kann.
#!/usr/bin/env bash
# Apply the same backport commit to all actively supported release branches
set -euo pipefail
COMMIT_SHA="8f3a1c2"
SUPPORTED_BRANCHES=("release/2.3.x" "release/2.4.x" "release/2.5.x")
for branch in "${SUPPORTED_BRANCHES[@]}"; do
echo "Backporting $COMMIT_SHA to $branch"
git checkout "$branch"
git pull origin "$branch"
if git cherry-pick -x "$COMMIT_SHA"; then
git push origin "$branch"
echo "OK: $branch updated"
else
echo "CONFLICT: $branch needs manual resolution" >&2
git cherry-pick --abort
fi
done
7. Release-Branches mit CI/CD-Pipelines koordinieren
CI/CD-Pipelines sollten Release-Branches und Tags unterschiedlich behandeln, weil sie unterschiedliche Vertrauensstufen repraesentieren. Ein Push auf einen release/*-Branch loest typischerweise einen Deploy auf eine Staging- oder UAT-Umgebung aus, in der Kunden oder QA die Stabilisierung final abnehmen. Ein neuer, signierter Tag im Format v*.*.* hingegen loest den Produktions-Deploy aus, weil ein Tag einen bewusst freigegebenen, unveraenderlichen Stand markiert und damit als verlaesslicherer Ausloeser gilt als ein sich weiterentwickelnder Branch.
Diese Trennung reduziert das Risiko versehentlicher Produktions-Deployments erheblich, weil ein einfacher Commit auf den Release-Branch niemals automatisch live geht, sondern erst nach expliziter Tag-Erstellung. In GitLab CI oder GitHub Actions laesst sich das über Regeln steuern, die auf den Ref-Typ und Namensmuster pruefen. Fuer Magento-Deployments bedeutet das konkret: Staging-Deploys laufen bei jedem Push auf den Release-Branch inklusive Composer-Install und Setup-Upgrade, während der Produktions-Deploy erst nach dem Tag mit zusaetzlichen Freigabeschritten wie Wartungsmodus und Cache-Warm-up laeuft.
# .gitlab-ci.yml excerpt: branch-triggered staging, tag-triggered production
stages:
- test
- deploy-staging
- deploy-production
deploy_staging:
stage: deploy-staging
script:
- composer install --no-dev --optimize-autoloader
- bin/magento setup:upgrade
- bin/magento cache:flush
rules:
- if: '$CI_COMMIT_BRANCH =~ /^release\/.*/'
deploy_production:
stage: deploy-production
script:
- bin/magento maintenance:enable
- composer install --no-dev --optimize-autoloader
- bin/magento setup:upgrade
- bin/magento setup:di:compile
- bin/magento cache:warm-up
- bin/magento maintenance:disable
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
when: manual
8. Merge-back: Release-Branch zurueck nach main/develop
Nach dem erfolgreichen Release muss der Release-Branch zurueck in main und develop gemerged werden, damit alle während der Stabilisierung eingeflossenen Fixes auch in der laufenden Entwicklung ankommen. Wird dieser Schritt vergessen, tritt derselbe Bug spaeter erneut auf, weil der Fix nur im Release-Branch existierte und die Weiterentwicklung auf develop ihn nie erhalten hat. Der Merge-back sollte fester Bestandteil der Release-Checkliste sein, kein optionaler Nachgedanke.
In der Praxis laeuft der Merge-back am saubersten mit einem regulaeren Merge-Commit statt Rebase, weil dadurch die Historie des Release-Branches inklusive aller Hotfix-Commits nachvollziehbar erhalten bleibt. Konflikte entstehen vor allem, wenn develop seit dem Abzweigen bereits denselben Codebereich veraendert hat, und sind meist ein gutes Signal dafuer, dass ein Fix ohnehin schon anderweitig geloest wurde. Nach dem Merge-back kann der Release-Branch für abgeschlossene Major- oder Minor-Versionen archiviert werden, während aktiv unterstuetzte Linien wie 2.4.x als Langzeit-Branch bestehen bleiben.
9. Release-Branches im direkten Vergleich
Die folgende Tabelle stellt riskante, unstrukturierte Release-Praktiken den empfohlenen, strukturierten Alternativen gegenueber. Die Unterschiede wirken auf den ersten Blick klein, entscheiden in der Praxis aber darueber, ob ein Hotfix in wenigen Minuten sicher ausgeliefert werden kann oder eine Nacht voller manueller Korrekturen nach sich zieht.
| Aufgabe | Riskant / unstrukturiert | Strukturierte Praxis | Vorteil |
|---|---|---|---|
| Hotfix ausliefern | Hotfix direkt auf main | Hotfix-Branch von Release-Tag | Fix bezieht sich auf exakt den freigegebenen Stand |
| Versionsnummern vergeben | Keine Versionierung / willkuerliche Nummern | Semantic Versioning mit fester Bump-Regel | Versionsnummer verraet Risiko eines Updates |
| Release markieren | Leichte Tags ohne Nachricht | Annotierte, signierte Tags | Unveraenderlicher, nachweisbarer Auslieferungspunkt |
| Fix in aeltere Version bringen | Fix manuell in jeden Branch neu eingetippt | Cherry-Pick mit -x und Backport-Referenz | Nachvollziehbar, keine abweichenden Implementierungen |
| Produktion deployen | Deploy bei jedem Commit ohne Freigabe | Tag-getriggerter Produktions-Deploy nach Freigabe | Keine versehentlichen Live-Deployments |
Der gemeinsame Nenner der strukturierten Spalte: Jeder Schritt hinterlaesst eine nachvollziehbare Spur in der Git-Historie, von der Branch-Benennung über die Tag-Signatur bis zur Commit-Referenz beim Cherry-Pick. Diese Nachvollziehbarkeit ist genau das, was ein Audit oder ein Debugging-Einsatz Monate spaeter braucht, wenn geklaert werden muss, welche Version welchen Fix wann erhalten hat.
Mironsoft
Release-Management, Versionierungsstrategie und CI/CD-Pipelines für Magento-Teams
Release-Prozess strukturieren, bevor der naechste Hotfix draengt?
Wir bauen Release-Branch-Workflows, Semantic-Versioning-Konventionen und CI/CD-Pipelines auf, die Staging- und Produktions-Deployments sauber trennen, damit euer Magento-Team Releases planbar und ohne naechtliche Feuerwehreinsaetze ausliefert.
Branching-Strategie
Release-, Hotfix- und Support-Branches passend zu eurem Support-Zeitraum aufsetzen
Versionierung & Tagging
Semantic Versioning, signierte Tags und automatisierte Changelogs einfuehren
CI/CD-Integration
Branch- und Tag-getriggerte Pipelines für Staging und Produktion konfigurieren
10. Zusammenfassung
Strukturierte Release-Branches lösen ein wiederkehrendes Problem: Stabilisierung und Weiterentwicklung duerfen nicht denselben Branch teilen, sonst blockieren sie sich gegenseitig. Ein Release-Branch, abgezweigt bei Code Freeze, nimmt ab diesem Punkt nur noch Bugfixes auf, während neue Features ungestoert auf develop weiterlaufen. Semantic Versioning mit MAJOR.MINOR.PATCH macht jede Versionsnummer aussagekraeftig, annotierte und signierte Tags markieren unveraenderliche, vertrauenswuerdige Auslieferungspunkte.
Cherry-Pick-Backporting bringt Fixes gezielt in aeltere unterstuetzte Linien, ohne die komplette Historie mitzunehmen, und eine klare Support-Matrix verhindert, dass Kunden auf aelteren Versionen unversorgt bleiben. CI/CD-Pipelines, die Branch-Pushes für Staging und Tag-Erstellung für Produktion unterschiedlich behandeln, reduzieren das Risiko versehentlicher Live-Deployments erheblich. Der Merge-back nach main und develop schließt den Kreis und stellt sicher, dass kein während der Stabilisierung entstandener Fix in der laufenden Entwicklung verloren geht.
Release-Branches und Versionierung, das Wichtigste auf einen Blick
Release-Branches
Bei Code Freeze von develop abzweigen, ab dann nur noch Bugfixes und Release-Vorbereitung, keine neuen Features.
Semantic Versioning
MAJOR für Breaking Changes, MINOR für neue Features, PATCH für Bugfixes. Feste Bump-Regel statt Bauchgefuehl.
Tags & Signierung
Annotierte Tags mit git tag -a, signiert mit git tag -s. Unveraenderlicher, vertrauenswuerdiger Auslieferungspunkt.
CI/CD-Trigger
Branch-Push loest Staging-Deploy aus, Tag-Erstellung loest Produktions-Deploy aus. Trennt Vorschau von Live-Gang.