lesbare Ankündigungen statt roher Commit-Listen
Release Notes richten sich an Nutzer und Stakeholder, nicht an Entwickler, und brauchen deshalb einen anderen Ton als ein technischer Changelog. Dieser Artikel zeigt, wie ein Bash-Skript aus dem Commit-Bereich zwischen zwei Tags automatisch lesbare Release Notes mit Mitwirkenden, hervorgehobenen Highlights und Vergleichslink erzeugt und direkt an die GitHub oder GitLab Release API übergibt.
Inhaltsverzeichnis
- 1. Release Notes sind kein Changelog
- 2. Den Commit-Bereich zwischen zwei Tags bestimmen
- 3. Mitwirkende automatisch auflisten
- 4. Wichtigste Änderungen als Highlights hervorheben
- 5. Nach nutzerrelevanten Kategorien gruppieren
- 6. Vergleichslink zum vorherigen Release einfügen
- 7. Textbausteine für einen konsistenten Ton
- 8. Release Notes an die Release API übergeben
- 9. Release Notes Generator im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Release Notes sind kein Changelog
Ein Changelog protokolliert kontinuierlich jede einzelne technische Änderung eines Projekts, oft in einer einzigen, stetig wachsenden Datei. Release Notes dagegen sind eine punktuelle Zusammenfassung genau einer Veröffentlichung, geschrieben für Anwender, Kunden oder das Management, die keine Commit-Historie lesen wollen. Wer diese Unterscheidung ignoriert, produziert entweder zu technische Release Notes oder einen Changelog, der wie eine Marketing-Nachricht klingt.
Der Kern eines guten Skripts für Release Notes liegt darin, aus derselben Git-Historie zwei völlig unterschiedliche Ausgaben zu erzeugen: technische Details für Entwickler bleiben im Changelog, während die Release Notes nur die für Nutzer sichtbaren, spürbaren Änderungen hervorheben, angereichert um Kontext wie Mitwirkende und einen direkten Vergleichslink.
Dieser Artikel baut ein Bash-Skript, das genau diese Trennung umsetzt: Es liest denselben Commit-Bereich wie ein Changelog Generator aus, wendet aber andere Filter- und Formatierungsregeln an, um am Ende Release Notes zu erzeugen, die sich direkt auf einer GitHub- oder GitLab-Release-Seite veröffentlichen lassen.
2. Den Commit-Bereich zwischen zwei Tags bestimmen
Anders als ein kontinuierlich aktualisierter Changelog beziehen sich Release Notes immer auf genau ein abgeschlossenes Zeitfenster, meist den Bereich zwischen zwei aufeinanderfolgenden Tags. Das Skript muss deshalb sowohl den aktuellen als auch den vorherigen Tag zuverlässig ermitteln, typischerweise über git tag --sort=-v:refname, um nach Versionsnummer statt nach Erstellungsdatum zu sortieren.
Ein häufiger Stolperstein bei Release Notes: Lightweight-Tags ohne Annotation verhalten sich in einigen Git-Befehlen anders als annotierte Tags. Ein robustes Skript sollte deshalb explizit mit git for-each-ref arbeiten, das beide Tag-Typen einheitlich behandelt, statt sich auf git describe allein zu verlassen, das primär für annotierte Tags gedacht ist.
#!/usr/bin/env bash
# determine-range.sh — find the commit range for release notes
set -euo pipefail
determine_release_range() {
local -a tags=()
while IFS= read -r tag; do
tags+=("$tag")
done < <(git for-each-ref --sort=-v:refname --format='%(refname:short)' refs/tags)
if [[ ${#tags[@]} -lt 1 ]]; then
echo "[ERROR] No tags found in repository" >&2
exit 1
fi
local current_tag="${tags[0]}"
local previous_tag="${tags[1]:-}"
echo "current=${current_tag}"
echo "previous=${previous_tag}"
echo "range=${previous_tag:+${previous_tag}..}${current_tag}"
}
determine_release_range
3. Mitwirkende automatisch auflisten
Ein Merkmal, das Release Notes von einem technischen Changelog unterscheidet, ist die namentliche Würdigung der Mitwirkenden. Gerade in Open-Source-Projekten oder größeren Teams schafft eine Liste der Autoren pro Release Anerkennung und Transparenz darüber, wer an einer Version beteiligt war. git shortlog liefert diese Information bereits fertig aggregiert und nach Anzahl der Commits sortiert.
Für Release Notes sollte die Liste zusätzlich dedupliziert werden, falls dieselbe Person mit unterschiedlichen E-Mail-Adressen committet hat, etwa privat und geschäftlich. Eine einfache Normalisierung über den Namen statt der E-Mail-Adresse reduziert doppelte Einträge, ohne eine vollständige Mailmap-Datei pflegen zu müssen.
#!/usr/bin/env bash
# list-contributors.sh — list unique contributors for the release notes
set -euo pipefail
list_contributors() {
local range="$1"
git log "$range" --no-merges --format='%an' | sort -u
}
range="${1:?Usage: list-contributors.sh <range>}"
echo "## Contributors"
echo
list_contributors "$range" | while IFS= read -r name; do
echo "- ${name}"
done
4. Wichtigste Änderungen als Highlights hervorheben
Ein reiner Abdruck aller Commit-Betreffzeilen wäre für Release Notes zu unstrukturiert, da nicht jede Änderung für Nutzer gleich relevant ist. Eine praktikable Heuristik: Commits mit dem Präfix feat: gelten als potenzielle Highlights, während chore:, test: und ci: für Nutzer irrelevant sind und aus den Release Notes herausgefiltert werden sollten, obwohl sie im technischen Changelog durchaus auftauchen dürfen.
Zusätzlich lohnt sich ein Blick auf die Länge und den Detailgrad der Commit-Nachricht: Nachrichten mit einem ausführlichen Body enthalten häufig genau die Beschreibung, die sich fast unverändert in die Release Notes übernehmen lässt, während knappe Einzeiler oft zu technisch formuliert sind, um sie direkt an Endnutzer zu kommunizieren.
#!/usr/bin/env bash
# extract-highlights.sh — pick user-facing changes for release notes
set -euo pipefail
extract_highlights() {
local range="$1"
git log "$range" --no-merges --format='%s' |
grep -E '^feat(\(.+\))?!?: ' |
sed -E 's/^feat(\(.+\))?!?: //'
}
range="${1:?Usage: extract-highlights.sh <range>}"
echo "## Highlights"
echo
extract_highlights "$range" | while IFS= read -r line; do
echo "- ${line^}"
done
5. Nach nutzerrelevanten Kategorien gruppieren
Während ein Changelog Generator streng nach Commit-Typ gruppiert, orientieren sich gute Release Notes an nutzerrelevanten Kategorien wie Neue Funktionen, Verbesserungen und Behobene Probleme. Diese Kategorien überschneiden sich zwar mit den technischen Commit-Typen, sind aber bewusst umformuliert, um für Leser ohne technischen Hintergrund verständlich zu bleiben.
Ein Beispiel: Ein perf: Commit wird im technischen Changelog als Performance-Optimierung geführt, in den Release Notes aber möglicherweise als Verbesserung unter Schnellere Ladezeiten zusammengefasst, gemeinsam mit anderen performance-relevanten Änderungen, die für Nutzer als ein einziger, spürbarer Vorteil erscheinen.
6. Vergleichslink zum vorherigen Release einfügen
Auch wenn Release Notes primär für nicht-technische Leser gedacht sind, sollte am Ende immer ein Link zum vollständigen Diff zwischen dem aktuellen und dem vorherigen Tag stehen. Interessierte technische Nutzer, etwa Partner-Entwickler oder das eigene Support-Team, können so bei Bedarf jederzeit tiefer in die tatsächlichen Code-Änderungen einsteigen, ohne dass die Release Notes selbst mit Details überladen werden müssen.
Der Vergleichslink lässt sich unmittelbar aus den beiden Tag-Namen und der bekannten Repository-URL zusammensetzen, etwa in der Form https://github.com/org/repo/compare/v1.4.0...v1.5.0. Bei GitLab-gehosteten Projekten unterscheidet sich nur das URL-Schema, das Prinzip bleibt identisch.
7. Textbausteine für einen konsistenten Ton
Automatisch generierte Release Notes wirken schnell roboterhaft, wenn jede Version exakt dieselbe Struktur ohne jede Variation zeigt. Ein einfacher Trick: Ein Array mit mehreren Formulierungsvarianten für die Einleitung, aus dem das Skript pro Lauf zufällig eine Variante auswählt, sodass aufeinanderfolgende Release Notes nicht wortwörtlich identisch beginnen.
Wichtiger als stilistische Variation ist jedoch ein konsistentes Grundgerüst: Einleitung, Highlights, vollständige Kategorienliste, Mitwirkende, Vergleichslink, immer in derselben Reihenfolge. Diese Konsistenz sorgt dafür, dass Leser sich über mehrere Versionen hinweg in den Release Notes sofort zurechtfinden, unabhängig von den inhaltlichen Details der jeweiligen Version.
#!/usr/bin/env bash
# build-release-notes.sh — assemble the final release notes document
set -euo pipefail
version="$1"
range="$2"
intros=(
"This release focuses on"
"In this update, we shipped"
"Here is what changed in"
)
intro="${intros[$((RANDOM % ${#intros[@]}))]}"
{
echo "# ${version}"
echo
echo "${intro} ${version}."
echo
bash extract-highlights.sh "$range"
echo
bash list-contributors.sh "$range"
echo
echo "**Full diff:** https://github.com/mironsoft/example-repo/compare/${range/../.../.../}"
} > release-notes.md
echo "[OK] release-notes.md generated for ${version}"
8. Release Notes an die Release API übergeben
Statt die fertigen Release Notes manuell in die GitHub- oder GitLab-Oberfläche zu kopieren, lässt sich der gesamte Vorgang über die jeweilige Release API automatisieren. Für GitHub genügt ein curl Aufruf gegen /repos/{owner}/{repo}/releases mit dem generierten Markdown-Text im body Feld des JSON-Payloads.
Wichtig für die Automatisierung: Sonderzeichen und Zeilenumbrüche im generierten Text müssen korrekt für JSON escaped werden, wofür sich jq -Rs . anbietet, das eine mehrzeilige Textdatei zuverlässig in einen gültigen JSON-String umwandelt, ohne manuelles Escaping von Anführungszeichen oder Newlines.
#!/usr/bin/env bash
# publish-release.sh — push release notes to the GitHub Releases API
set -euo pipefail
readonly REPO="mironsoft/example-repo"
readonly TOKEN="${GITHUB_TOKEN:?Set GITHUB_TOKEN}"
version="$1"
body_json="$(jq -Rs . < release-notes.md)"
payload=$(jq -n \
--arg tag "$version" \
--argjson body "$body_json" \
'{ tag_name: $tag, name: $tag, body: $body, draft: false, prerelease: false }')
curl -sf -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Accept: application/vnd.github+json" \
-d "$payload" \
"https://api.github.com/repos/${REPO}/releases" > /dev/null
echo "[OK] Release ${version} published with generated release notes"
9. Release Notes Generator im Vergleich
GitHub bietet mit den automatisch generierten Release Notes ein eingebautes Feature, das Pull-Request-Titel gruppiert. Für Projekte, die konsequent über Pull Requests statt direkte Commits arbeiten, ist dieses eingebaute Werkzeug oft ausreichend. Ein eigenes Bash-Skript lohnt sich, sobald individuelle Kategorien, Mitwirkenden-Formatierung oder eine Cross-Plattform-Veröffentlichung auf mehreren Release-Kanälen gebraucht werden.
| Ansatz | Anpassbarkeit | Mitwirkenden-Liste | Geeignet für |
|---|---|---|---|
| Bash Release Notes Generator | Vollständig | Individuell formatiert | Cross-Plattform, individuelle Kategorien |
| GitHub Auto-Generated Notes | Begrenzt konfigurierbar | Nach PR-Autor | Reine GitHub-PR-Workflows |
| Manuelle Release Notes | Vollständig | Manuell, fehleranfällig | Sehr seltene Releases |
| Release-Please (Google) | Konfigurierbar über Presets | Begrenzt | Node-lastige Google-Style-Projekte |
Für Teams mit eigenem Release-Kanal, etwa einer internen Status-Seite zusätzlich zu GitHub, ist ein selbst gebauter Ansatz für Release Notes oft die einzige Möglichkeit, denselben Text konsistent an mehrere Ziele gleichzeitig zu verteilen.
Mironsoft
Shell-Automatisierung, Release-Management und Deployment-Infrastruktur
Release Notes, die sich automatisch schreiben?
Wir bauen ein Skript, das aus eurer Git-Historie lesbare Release Notes mit Mitwirkenden, Highlights und Vergleichslink erzeugt und direkt an GitHub, GitLab oder eure eigene Status-Seite übergibt.
Skript-Entwicklung
Individueller Release Notes Generator passend zu eurem Ton
API-Integration
Automatische Veröffentlichung auf GitHub, GitLab oder eigenen Kanälen
Release-Prozess
Einbindung in bestehende CI/CD-Pipelines und Tag-Workflows
10. Zusammenfassung
Automatisch generierte Release Notes unterscheiden sich bewusst von einem technischen Changelog: Sie richten sich an Nutzer, heben Highlights statt jeder einzelnen Änderung hervor und würdigen Mitwirkende namentlich. Ein Bash-Skript, das den Commit-Bereich zwischen zwei Tags ausliest, feat-Commits filtert und einen Vergleichslink ergänzt, liefert die Grundlage für konsistente Release Notes bei jeder Veröffentlichung.
Der letzte Schritt, die direkte Veröffentlichung über die GitHub- oder GitLab-Release-API, macht aus dem Skript einen vollständigen Teil des Release-Prozesses. Statt Release Notes manuell zu formatieren und in eine Web-Oberfläche zu kopieren, entsteht ein einziger Befehl, der Text generiert und gleichzeitig veröffentlicht.
Release Notes aus Git Log — Das Wichtigste auf einen Blick
Abgrenzung zum Changelog
Release Notes richten sich an Nutzer, ein Changelog an Entwickler, beide entstehen aber aus derselben Historie.
Highlights statt Vollständigkeit
feat-Commits werden gefiltert und hervorgehoben, technische chore- und ci-Commits bleiben außen vor.
Mitwirkende
git shortlog liefert eine deduplizierte Liste der Autoren pro Release automatisch.
Veröffentlichung
Direkte Übergabe an die GitHub oder GitLab Release API mit korrekt escaptem JSON-Text.