𝗣𝗮𝗰𝗸𝗮𝗴𝗲.𝗷𝘀𝗼𝗻 𝘃𝘀 𝗚𝗼.𝗺𝗼𝗱: 𝗪𝗼 𝗶𝘀𝘁 𝗱𝗶𝗲 𝗩𝗲𝗿𝘀𝗶𝗼𝗻𝘀𝗶𝗻𝗳𝗼 𝗴𝗲𝗯𝗹𝗶𝗲𝗯𝗲𝗻?
Wenn du von JavaScript zu Go wechselst, wird dich eine Sache überraschen.
In einer package.json-Datei steht die Version direkt ganz oben. Du kannst sie lesen. Du kannst sie in einem Pull Request ändern. Du kannst nach ihr suchen. Sie ist eine Tatsache, die direkt in deinem Code lebt.
Öffne nun eine go.mod-Datei. Die Version ist nicht da.
Das ist kein Fehler. Es ist eine bewusste Entscheidung.
Go verwendet kein Versionsfeld für dein eigenes Modul. Stattdessen nutzt Go Git-Tags.
Um eine Version in Go festzulegen, machst du Folgendes:
- git tag v1.2.3
- git push origin v1.2.3
Der Git-Tag ist die „Single Source of Truth“. Wenn jemand go get ausführt, schaut Go in die Tags deines Repositorys, um den richtigen Commit zu finden.
Dieses Design hat eine große Stärke. Eine Version kann niemals auf den falschen Code zeigen. Bei npm können der veröffentlichte Code und der getaggte Quellcode auseinanderdriften. In Go sind sie dasselbe, da die Version ein Zeiger auf einen Commit ist.
Dies verändert jedoch deinen Workflow in mehreren Punkten:
- Das Finden deiner Version erfordert einen Befehl. Du musst
git describe --tagsausführen, anstatt einfach in eine Datei zu schauen. - Versionssprünge erscheinen nicht in Code-Reviews. Ein Tag-Push ist keine Code-Änderung und erscheint daher nicht in einem Pull Request.
- Lokale Builds verwenden Pseudo-Versionen. Bis du einen Commit taggst, siehst du eine lange Zeichenfolge aus Zahlen und Hashes anstelle einer sauberen Version wie
v1.2.3. - Major-Versionen ändern deinen Import-Pfad. Bei npm änderst du die Versionsnummer, behältst aber den Paketnamen bei. In Go erfordern v2 und höher eine Pfadänderung wie
/v2. Dies ermöglicht es einem Programm, v1 und v2 derselben Bibliothek gleichzeitig zu verwenden, ohne dass es zu Konflikten kommt.
Die meisten anderen Ökosysteme speichern die Version in einer Datei:
- Node:
package.json - Rust:
Cargo.toml - Python:
pyproject.toml - Java:
pom.xml - .NET:
.csproj
Go ist anders. Es verlässt sich ausschließlich auf Git-Tags.
Wenn du möchtest, dass deine Go-Binärdatei eine saubere Version anzeigt, kannst du diese während des Build-Prozesses mittels ldflags injizieren. Viele Entwickler nutzen zudem Tools wie goreleaser, um den Tag- und Release-Prozess zu automatisieren.
Die beiden Modelle repräsentieren unterschiedliche Prioritäten:
- Datei-basierte Versionen sind leicht zu lesen und zu überprüfen. Das Risiko besteht darin, dass die Datei vom tatsächlichen Code abweichen kann.
- Tag-basierte Versionen sind nicht zu fälschen. Der Nachteil ist, dass sie schwerer einzusehen und zu verwalten sind.
Go hat sich für das Tag-Modell entschieden, um sicherzustellen, dass das Manifest immer mit dem Code übereinstimmt.
Für alle, die Go-Code veröffentlichen: Wie fühlt sich das Tag-only-Modell in eurem Arbeitsalltag an? Würdet ihr etwas daran ändern?
Quelle: https://dev.to/dalirnet/packagejson-vs-gomod-where-did-the-version-field-go-3301