Mit Semantic Versioning sauber umsetzen
Tags markieren Releasepunkte in der Git Historie, aber erst eine konsequente Strategie aus annotierten Tags, klarer Semantic Versioning Konvention und automatisierter Ableitung macht sie für CI Pipelines und Deployment Prozesse wirklich zuverlässig nutzbar.
Inhaltsverzeichnis
- 1. Warum uneinheitliche Tags zum Problem im Release Prozess werden
- 2. Annotierte Tags gegenüber leichten Tags
- 3. Semantic Versioning konsequent in der Tag Struktur abbilden
- 4. Release Tags kryptografisch signieren
- 5. Versionsnummern automatisiert aus der Tag Historie ableiten
- 6. Tag basierte Release Automatisierung in CI Pipelines
- 7. Tags gegenüber dedizierten Release Branches
- 8. Best Practices für eine konsistente Tag Strategie
- 9. Typische Fallstricke bei Tag Strategien
- 10. Zusammenfassung
- 11. FAQ
1. Warum uneinheitliche Tags zum Problem im Release Prozess werden
Ohne klare Konvention entstehen in gewachsenen Repositories schnell Tags in unterschiedlichsten Formaten: v1.2.3 neben 1.2.3, release-2024-05 neben rc1, manche annotiert, andere leicht und ohne jeden Kontext. Sobald ein CI System oder ein Deployment Skript automatisiert die neueste Version ermitteln oder einen Changelog generieren soll, scheitert das an dieser Uneinheitlichkeit, weil sich Versionen nicht mehr zuverlässig vergleichen oder sortieren lassen.
Eine konsequente Tag Strategie löst zwei Probleme gleichzeitig: Sie macht Releases für Menschen nachvollziehbar lesbar und liefert gleichzeitig eine maschinell auswertbare Grundlage für Automatisierung. Semantic Versioning bietet dafür eine etablierte, klar definierte Struktur, die sich direkt auf Git Tags abbilden lässt.
2. Annotierte Tags gegenüber leichten Tags
Ein leichter Tag ist technisch nichts weiter als ein benannter Zeiger auf einen Commit, vergleichbar mit einem Branch, der sich nur nicht automatisch mitbewegt. Ein annotierter Tag dagegen ist ein eigenständiges Git Objekt mit Tagger, Zeitstempel, Nachricht und optionaler kryptografischer Signatur, das selbst wieder auf den referenzierten Commit zeigt.
Für Releases sind annotierte Tags praktisch immer die richtige Wahl, weil nur sie Metadaten wie eine Release Nachricht und einen nachvollziehbaren Zeitstempel unabhängig vom referenzierten Commit tragen. Leichte Tags eignen sich höchstens für kurzlebige, rein lokale Markierungen, etwa um sich temporär einen Commit zu merken, sollten aber nie für offizielle Releases verwendet werden.
# Leichter Tag: nur ein Zeiger, keine Metadaten
git tag v1.2.3-temp
# Annotierter Tag: eigenständiges Objekt mit Nachricht und Zeitstempel
git tag -a v1.2.3 -m "Release 1.2.3: Sicherheitsfix für Session Handling"
# Unterschied direkt einsehen
git cat-file -p v1.2.3
3. Semantic Versioning konsequent in der Tag Struktur abbilden
Semantic Versioning definiert eine Versionsnummer als MAJOR.MINOR.PATCH, wobei MAJOR inkompatible API Aenderungen kennzeichnet, MINOR rückwärtskompatible neue Funktionalität und PATCH rückwärtskompatible Fehlerbehebungen. Diese Struktur lässt sich direkt und ohne Modifikation als Tag Name verwenden, üblicherweise mit einem führenden v Präfix, etwa v2.4.0, um Versionstags klar von anderen Tag Typen zu unterscheiden.
Vorabversionen und Build Metadaten haben in Semantic Versioning eine feste Syntax: Ein Bindestrich Suffix wie -rc.1 oder -beta.2 markiert eine Vorabversion, ein Plus Suffix wie +build.42 markiert reine Build Metadaten ohne Einfluss auf die Versionsvergleichslogik. Beide Suffixe lassen sich direkt im Tag Namen abbilden, etwa v2.4.0-rc.1, solange das genutzte Tooling diese Syntax korrekt interpretiert.
# Regulärer Release Tag nach Semantic Versioning
git tag -a v2.4.0 -m "Release 2.4.0"
# Release Candidate vor der finalen Veröffentlichung
git tag -a v2.4.0-rc.1 -m "Release Candidate 1 für 2.4.0"
# Patch Release für einen kritischen Bugfix
git tag -a v2.4.1 -m "Release 2.4.1: Hotfix für Datenexport"
4. Release Tags kryptografisch signieren
Für öffentlich verteilte Software oder sicherheitskritische interne Projekte reicht eine einfache Textnachricht am Tag oft nicht aus, um die Herkunft zweifelsfrei zu belegen. Mit git tag -s lässt sich ein Tag mit dem konfigurierten GPG Schlüssel signieren, wodurch später jederzeit überprüft werden kann, ob der Tag tatsächlich von der berechtigten Person stammt und seit der Erstellung nicht verändert wurde.
Die Verifikation erfolgt mit git tag -v oder automatisch beim Checkout eines signierten Tags, sofern gpg.program korrekt konfiguriert ist und der öffentliche Schlüssel des Signierenden lokal bekannt ist. In CI Pipelines lässt sich diese Prüfung als Gate vor jedem Deployment einbauen, um sicherzustellen, dass ausschließlich verifizierte Releases in Produktion gelangen.
# Release Tag mit dem konfigurierten GPG Schlüssel signieren
git tag -s v2.4.0 -m "Release 2.4.0"
# Signatur eines Tags verifizieren
git tag -v v2.4.0
# Signaturstatus in git log anzeigen
git log --show-signature -1 v2.4.0
5. Versionsnummern automatisiert aus der Tag Historie ableiten
Statt Versionsnummern manuell in Konfigurationsdateien zu pflegen, lässt sich die aktuelle Version direkt aus der Git Historie ableiten. Der Befehl git describe --tags findet den nächsten erreichbaren Tag ausgehend vom aktuellen Commit und ergänzt ihn um die Anzahl der Commits seit diesem Tag sowie den abgekürzten Commit Hash, was sich hervorragend als Basis für automatisch generierte Entwicklungsversionen eignet.
Für strikte Semantic Versioning Konformität muss die Ausgabe von git describe meist noch leicht angepasst werden, weil das Standardformat mit einem zusätzlichen Bindestrich und Commit Zähler nicht direkt der Semver Syntax entspricht. Viele Release Automatisierungstools wie semantic-release oder GitVersion übernehmen diese Umformatierung automatisch und leiten daraus konsistent die nächste Versionsnummer ab.
# Nächsten erreichbaren Tag ab dem aktuellen Commit ermitteln
git describe --tags
# Ausgabeformat: v2.4.0-14-g3a91f2c
# 14 Commits seit v2.4.0, aktueller Commit beginnt mit 3a91f2c
# Nur den zuletzt erreichten Tag ohne Zusatzinformation ausgeben
git describe --tags --abbrev=0
6. Tag basierte Release Automatisierung in CI Pipelines
Ein verbreitetes Muster ist, einen Release ausschließlich durch das Pushen eines passenden Tags auszulösen, statt Releases manuell in einem separaten System zu erstellen. Die CI Pipeline reagiert dabei gezielt auf Tags, die dem konfigurierten Muster entsprechen, baut daraus Artefakte, generiert einen Changelog aus den Commit Messages seit dem vorherigen Tag und veröffentlicht das Ergebnis automatisiert.
Wichtig ist dabei eine klare Trennung zwischen Tags, die einen Release auslösen sollen, und Tags für andere Zwecke, etwa interne Markierungen. Ein konsequentes Präfix wie v in Kombination mit einem Pipeline Filter auf genau dieses Muster verhindert, dass versehentlich gesetzte Tags ungewollt einen Produktivdeploy auslösen.
# Beispiel: CI Pipeline reagiert nur auf Tags nach Semver Muster
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
7. Tags gegenüber dedizierten Release Branches
Tags markieren einen einzelnen, unveränderlichen Zeitpunkt in der Historie und eignen sich hervorragend, um genau diesen einen Commit als Release zu kennzeichnen. Sobald aber nach einem Release noch gezielte Hotfixes für genau diese Version nötig sind, ohne dass bereits fertig entwickelte Funktionalität aus dem main Branch versehentlich mit ausgeliefert wird, reicht ein reiner Tag nicht mehr aus, weil sich auf einem Tag selbst keine weiteren Commits aufbauen lassen.
In solchen Fällen ergänzt ein dedizierter Release Branch wie release/2.4 die Tag Strategie sinnvoll: Der Branch existiert parallel zu main, erhält ausschließlich Cherry Picks für kritische Fixes, und jeder Fix wird wiederum mit einem eigenen Patch Tag wie v2.4.1 versehen. Diese Kombination aus langlebigem Release Branch und kurzlebigen, unveränderlichen Tags pro Veröffentlichung deckt sowohl die Nachverfolgbarkeit einzelner Releases als auch die Möglichkeit gezielter Nacharbeit ab.
8. Best Practices für eine konsistente Tag Strategie
Release Tags sollten immer annotiert und in sicherheitsrelevanten Projekten zusätzlich signiert sein, niemals leichte Tags. Ein einheitliches Präfix, meist v, und eine strikte Einhaltung der MAJOR.MINOR.PATCH Struktur sind Grundvoraussetzung dafür, dass automatisierte Tools Versionen zuverlässig vergleichen und sortieren können.
Die Entscheidung, wann MAJOR, MINOR oder PATCH erhöht wird, sollte im Team dokumentiert und idealerweise durch automatisierte Analyse von Commit Messages nach Conventional Commits Konvention unterstützt werden, statt bei jedem Release erneut manuell diskutiert zu werden.
9. Typische Fallstricke bei Tag Strategien
Ein häufiger Fehler ist das nachträgliche Verschieben eines bereits veröffentlichten Tags mit git tag -f, weil dadurch derselbe Versionsname plötzlich auf unterschiedliche Commits zeigt, je nachdem wann ein Nutzer den Tag zuletzt gefetcht hat. Ein einmal veröffentlichter Release Tag sollte deshalb als unveränderlich betrachtet werden, ähnlich wie ein bereits gepushter Commit auf einem geteilten Branch.
Ein weiterer Fallstrick ist das Vermischen von Release Tags mit anderen Tag Typen im selben Namensraum, etwa Umgebungsmarkierungen wie staging-2024-05 neben Versionstags wie v2.4.0. Das erschwert automatisierte Filterung erheblich und führt früher oder später zu Pipeline Konfigurationen, die versehentlich auf falsche Tags reagieren.
| Tag Typ | Enthält Metadaten | Signierbar | Geeignet für Releases |
|---|---|---|---|
| Leichter Tag | Nein, nur Commit Referenz | Nein | Nicht geeignet |
| Annotierter Tag | Ja, Nachricht und Zeitstempel | Ja | Standard für Releases |
| Signierter annotierter Tag | Ja, zusätzlich kryptografisch verifizierbar | Ja, verpflichtend | Sicherheitskritische Releases |
| Vorabversion mit rc Suffix | Ja, wenn annotiert erstellt | Ja | Release Candidates vor Veröffentlichung |
Mironsoft
Git-Workflows, Branching-Strategien und CI-Hooks
Chaotische Git-Historie und unklare Branching-Regeln im Team?
Wir richten saubere Git-Workflows ein, klären Branching-Strategien fürs Team und automatisieren Qualitätschecks über Git-Hooks und CI-Pipelines, damit die Historie nachvollziehbar bleibt.
Workflow-Audit
Bestehende Branching-Strategie und Merge-Praxis auf Schwachstellen prüfen.
Hook-Automatisierung
Pre-Commit- und Pre-Push-Hooks für Linting, Tests und Commit-Konventionen einrichten.
Team-Schulung
Rebase, Cherry-Pick und Konfliktauflösung im Team praxisnah vermitteln.
10. Zusammenfassung
Tag Strategien
Empfohlener Tag Typ
Annotiert, bei Bedarf zusätzlich signiert
Format
vMAJOR.MINOR.PATCH nach Semantic Versioning
Kernbefehl
git tag -a v2.4.0 -m "Release 2.4.0"
Automatisierung
git describe --tags für Versionsermittlung