npm, Cargo, Composer und pip interpretieren dieselbe SemVer-Abkürzung alle unterschiedlich, und nur zwei der dreizehn von mir getesteten Bereichsausdrücke verhalten sich bei allen vieren identisch.
Ich habe für jeden Manager separate Parser geschrieben, deren offizielle Spezifikationen befolgt und dann jeden Bereich gegen eine Matrix aus neunzehn Versionsnummern getestet. Das 13 × 19-Raster (247 Zellen) zeichnete ein fragmentiertes Bild: Nur 17 Zellen lieferten bei jedem Tool die gleiche „Ja“- oder „Nein“-Antwort, und die meisten dieser 17 waren einstimmige Ablehnungen. Kurz gesagt: Die Tools stimmen viel häufiger bei einem „Nein“ überein als bei einem „Ja“.
Warum die Tools divergieren
Alle vier Manager geben an, Semantic Versioning zu folgen, doch jeder fügt seine eigenen Abkürzungsregeln hinzu.
- Caret (^) und dot-x – npm unterstützt Caret; pip ignoriert sowohl Caret als auch dot-x. Das allein führt zu einer Unstimmigkeit in 49 Zellen zwischen npm und pip.
- Versionen ohne Präfix – Cargo behandelt eine einfache
1.2.3als Caret-Bereich, was „kompatibel mit 1.x“ bedeutet. npm und Composer lesen denselben String als exakte Übereinstimmung und akzeptieren nur1.2.3. - Tilde (~) – Die Tilde von Cargo fixiert die Minor-Version (
~1.2passt auf1.2.*, aber nicht auf1.3.0). Die Tilde von Composer fixiert die Major-Version (~1.2passt auf1.*). Die beiden Interpretationen divergieren bei jeder Version, die die Minor-Komponente ändert.
Die Handhabung von Pre-Releases sorgt für eine weitere Überraschung. Ein Bereich wie ^1.2.3 schließt 2.0.0-rc.1 nicht ein, obwohl der numerische Teil niedriger als die Obergrenze ist. Die Regel lautet: Pre-Releases werden ausgeschlossen, es sei denn, der Bereich nennt explizit einen Pre-Release-Identifikator.
Die einzige sichere Syntax für alle Tools
Das Experiment zeigt, dass explizite Ungleichheitsbereiche – z. B. >=1.2.0 <2.0.0 – in npm, Cargo, Composer und pip auf die gleiche Weise funktionieren. Jeder Manager behandelt die beiden Grenzen als wörtliche numerische Limits, ohne versteckte Caret- oder Tilde-Semantik.
Wenn Sie „jede 1.x-Version, die mindestens 1.2 ist“ ausdrücken müssen, schreiben Sie es vollständig aus. Es kostet ein paar zusätzliche Zeichen, garantiert aber eine vorhersehbare Auflösung, egal wo der Code ausgeführt wird.
Wann Abkürzungen dennoch sinnvoll sind
Abkürzungen bleiben für Projekte in einer einzelnen Sprache attraktiv. Innerhalb eines reinen npm-Ökosystems fasst ^1.2.3 prägnant zusammen: „kompatibel mit zukünftigen Minor- und Patch-Releases“. Dasselbe gilt für das Caret von Cargo oder die Tilde von Composer, wenn man weiß, dass das konsumierende Tool sich nicht ändern wird. Die Gefahr besteht, wenn dasselbe Manifest über Sprachgrenzen hinweg wiederverwendet wird oder wenn ein CI-Job Abhängigkeiten aus mehreren Ökosystemen bezieht.
Fazit
Sich für die sprachübergreifende Kompatibilität auf SemVer-Abkürzungen zu verlassen, ist ein Glücksspiel. Der einzige zuverlässige Weg, um zu garantieren, dass eine Versionsbeschränkung überall dasselbe bedeutet, besteht darin, explizite Ungleichheiten zu schreiben. Wenn Sie Kürze benötigen, bleiben Sie innerhalb eines einzelnen Ökosystems; wenn Sie Konsistenz benötigen, tauschen Sie die Abkürzung gegen Klarheit ein.
