Wie schwer kann es sein, eine Versionsnummer in den Footer zu schreiben?
Ein Mini-Feature, drei Commits und eine Lektion über stille Fallbacks.
Manche Features sind so klein, dass man sie gar nicht plant. Unten im Footer sollte neben dem Copyright einfach die aktuelle Version der Seite stehen. Eine Zeile Template, ein bisschen Git, fertig. Dachte ich.
Versuch 1: git describe
Die Idee war simpel. Ich tagge Releases sowieso mit v1.0.x, also kann der Build die Version direkt aus Git holen:
function siteVersion() {
try {
return execFileSync('git', ['describe', '--tags', '--always'], { cwd: ROOT })
.toString().trim();
} catch {
return `v${JSON.parse(fs.readFileSync('package.json', 'utf8')).version}`;
}
}
git describe --tags ist dafür praktisch: Steht der Build genau auf einem Tag, kommt v1.0.4 raus. Gibt es danach noch Commits, wird daraus etwas wie v1.0.4-2-gabc1234, also „zwei Commits nach v1.0.4, aktueller Stand abc1234“. Für den Notfall gibt es noch einen Fallback auf die Version aus der package.json.
Lokal sah das super aus. Commit, Push, fertig.
Live: v1.0.0
Auf der echten Seite stand im Footer: v1.0.0. Das war die Version, die seit dem allerersten Commit unverändert in der package.json stand.
Der Grund: Meine Seite wird nicht lokal gebaut, sondern auf dem Server. Ein git push nach GitLab löst einen Webhook aus, Plesk holt sich den Stand und baut die Seite. Nur legt Plesk die Dateien in httpdocs/ ab, ohne .git-Verzeichnis. git describe hatte dort also gar kein Repository, ist fehlgeschlagen und der Fallback hat leise übernommen.
Versuch 2: Dann eben package.json
Einige Minuten später der nächste Commit: Weg mit Git, die Version kommt ab jetzt nur noch aus der package.json. Neue Releases mache ich mit npm version:
npm version patch # 1.0.4 → 1.0.5, mit Commit und Tag
git push --follow-tags origin main
npm version erhöht die Nummer, committet und setzt den passenden Git-Tag in einem Schritt. Das funktioniert und ist robust. Aber es fühlte sich wie ein Rückschritt an. Zwischenstände wie v1.0.4-2-gabc1234 sind weg, und vergesse ich das Release, zeigt der Footer wochenlang eine veraltete Nummer.
Versuch 3: Das Repo suchen
Also nochmal genauer hingeschaut. Plesk hat das Repository ja irgendwo, sonst könnte es nicht pullen. Gefunden! Es liegt als Bare-Repo unter ~/git/, also nur die Git-Daten ohne ausgecheckte Dateien. Und git describe braucht genau das, keine Arbeitskopie.
Mit --git-dir kann man Git sagen, wo das Repository liegt:
for (const gitDir of [undefined, ...pleskRepos()]) {
try {
const v = describe(gitDir);
return { version: v, source: gitDir ? `git (${gitDir})` : 'git' };
} catch { /* nächste Quelle */ }
}
return { version: pkg, source: 'package.json' };
Zuerst das Projektverzeichnis selbst (lokal), dann alle *.git-Ordner unter ~/git/, wobei Repos mit „themace“ im Namen nach vorne sortiert werden. Erst wenn nichts klappt, kommt die package.json.
Bonus-Stolperstein: „dubious ownership“
Seit einer Weile weigert sich Git, in Repositories zu arbeiten, die einem anderen Benutzer gehören. Das ist ein Sicherheitsfeature gegen manipulierte Repos auf geteilten Systemen. Auf dem Server gehört das Bare-Repo aber nicht unbedingt dem Benutzer, der den Build ausführt. Die Lösung für diesen einen Aufruf:
git -c safe.directory=* --git-dir ~/git/themace-de.git describe --tags --always
Die eigentliche Lektion: Fallbacks müssen laut sein
Das Spannendste an der Geschichte ist nicht Git und nicht Plesk. Mein erster Versuch war eigentlich richtig. Er hatte nur einen Fallback, der still war. Die Seite lief, nichts ist abgestürzt, und trotzdem war das Ergebnis falsch.
Deshalb schreibt der Build jetzt ins Deploy-Log, woher die Version kommt:
→ Version v1.0.4 (aus git (/var/www/vhosts/.../git/themace-de.git))
Steht da (aus package.json), weiß ich sofort, dass etwas nicht stimmt. Eine Zeile Log hätte mir zwei Commits erspart.
Fazit
Drei Commits für eine Versionsnummer im Footer. Was ich mitnehme:
- Lokal ist nicht gleich Server. Was auf meinem Rechner ein Git-Repo ist, ist auf dem Server nur ein Ordner mit Dateien.
- Bare-Repos reichen für Git-Abfragen.
--git-dirist dein Freund. - Ein Fallback ohne Log ist ein versteckter Bug. Wenn der Plan B greift, will ich das wissen.
Und ja: Die Versionsnummer steht jetzt unten im Footer. Schau ruhig mal nach. 👇