Wie erreicht man mit Git ein numerisches Versionsschema?


131

Meine Organisation erwägt, von SVN zu Git zu wechseln. Ein Argument gegen das Verschieben lautet wie folgt:

Wie machen wir die Versionierung?

Wir haben eine SDK-Distribution, die auf der NetBeans-Plattform basiert. Da es sich bei den SVN-Revisionen um einfache Nummern handelt, können wir sie verwenden, um die Versionsnummern unserer Plugins und SDK-Builds zu erweitern. Wie gehen wir damit um, wenn wir zu Git wechseln?

Mögliche Lösungen:

  • Verwenden der Build-Nummer von Hudson (Problem: Sie müssen Hudson überprüfen, um dies mit einer aktuellen Git-Version zu korrelieren.)
  • Manuelle Aktualisierung der Version für nächtliche und stabile (Problem: Lernkurve, menschliches Versagen)

Wenn jemand anderes auf ein ähnliches Problem gestoßen ist und es gelöst hat, würden wir gerne hören, wie.


3
Könnten Sie Ihren Hudson- Server (nicht Jenkins ?) Dazu bringen, gitnach jedem erfolgreichen Build automatisch ein Tag hinzuzufügen ? Dies hätte den zusätzlichen Vorteil, dass wirklich klar wird, bei welchen gitCommits Build-Probleme oder Testfehler auftreten, da sie nicht markiert sind.
Mark Booth


Als Randnotiz können Sie die Build-Anzahl zum Tag hinzufügen, indem Sie die Build-Zeiten verfolgen .
Shahbaz

Sie sind sich nicht sicher, ob es sich um eine praktikable Lösung handelt, aber wie wäre es, wenn Sie direkt vor jedem Build von Git in ein SVN-Repo exportieren? Dann bauen Sie einfach aus dem SVN-Repository auf - wenn Sie zentralisieren möchten, verwenden Sie stattdessen das Repository.
Jonny,

Antworten:


152

Verwenden Sie Tags , um Commits mit Versionsnummern zu kennzeichnen:

git tag -a v2.5 -m 'Version 2.5'

Tags nach oben verschieben - dies erfolgt nicht standardmäßig:

git push --tags

Verwenden Sie dann den Befehl describe :

git describe --tags --long

Dies gibt Ihnen eine Zeichenfolge des Formats:

v2.5-0-gdeadbee
^    ^ ^^
|    | ||
|    | |'-- SHA of HEAD (first seven chars)
|    | '-- "g" is for git
|    '---- number of commits since last tag
|
'--------- last tag

Stimmen Sie zu - es sollte einfach sein, die nächtliche Tag-Nummerierung zu automatisieren, wenn Sie dies benötigen, und die Heraufstufung auf Stable erfolgt sowieso manuell.
Nutzlos

20
Kleine Verbesserung: git describe --long --tags --dirty --always. 'Dirty' teilt Ihnen mit, ob es lokale Änderungen gab, als die Beschreibung durchgeführt wurde (was bedeutet, dass der Status des Repos nicht vollständig beschrieben werden kann). 'Immer' bedeutet, dass Sie keine Fehlermeldung erhalten, wenn keine Tags vorhanden sind. Es wird nur auf einen Commit-Hash zurückgegriffen. So können Sie 76001f2-dirtyals Beispiel bekommen. "Dreckig" zu sehen bedeutet natürlich, dass jemand durcheinander ist.
Mike Weller

1
Wie kann diese Arbeit , wenn das Etikett erzeugt letzte . Normalerweise möchten Sie, dass Builds in Zukunft die nächste Version Ihres Produkts haben. In diesem Fall müssen sie jedoch immer die letzte Version verwenden. Nur der endgültige, ausgelieferte Build hat die richtige Nummer.
void.pointer

@ void.pointer: Sicher, diese Versionsnummer beantwortet die Frage "Auf welchem ​​Release basierte dieses Commit?" und nicht "Auf welchem ​​Release wird dieses Commit ausgeführt?". Sie können Tags jedoch auch anders interpretieren. Wenn Sie beispielsweise HEADals taggen v2.5, können Sie dies genauso gut interpretieren wie den Beginn des 2.5-Release-Zyklus, dann taggen v2.5-releaseoder was auch immer Sie möchten.
Jon Purdy

8
Eine weitere kleine Verbesserung. Wenn Sie auch andere Tags haben möchten, aber ein speziell strukturiertes Tag für die Revisionsgenerierung verwenden möchten, können Sie die folgende --matchOption verwenden:git describe --long --tags --dirty --always --match 'v[0-9]\.[0-9]'
Alexander Amelkin,

42

Daraus sind für mich einige Projekte entstanden. Die beste Lösung, die ich bisher hatte, ist die Generierung einer Versionsnummer wie folgt:

xy <Anzahl der Commits> .r <Git-Hash>

In der Regel wird es von unserem Build-System mithilfe einer Kombination aus statischen Dateien oder Tags generiert, um die wichtigsten Revisionsnummern zu ermitteln git rev-list HEAD | wc -l(was schneller war als die Verwendung von git log) und git rev-parse HEAD. Die Argumentation war wie folgt:

  1. Wir brauchten die Möglichkeit, dass die Versionsverwaltung auf hoher Ebene explizit erfolgt (iexy).
  2. Bei der parallelen Entwicklung mussten wir NIE die gleiche Versionsnummer generieren.
  3. Wir wollten einfach herausfinden, woher eine Version kam.
  4. Als parallele Linien zusammengeführt wurden, wollten wir, dass die neue Version höher aufgelöst wird als jeder der Zweige.

Nummer 2 ist für die meisten Menschen unsichtbar, aber für die verteilte Quellcodeverwaltung sehr wichtig und sehr schwierig. SVN hilft dabei, indem es Ihnen eine einzelne Revisionsnummer gibt. Es stellt sich heraus, dass eine Commit-Zählung so nah wie möglich ist, während Sie auch # 4 auf magische Weise lösen. In Gegenwart von Zweigen ist dies immer noch nicht eindeutig. In diesem Fall fügen wir den Hash hinzu, der auch # 3 ordentlich löst.

Das meiste davon war für die Bereitstellung über Pythons Pip gedacht. Dies garantierte, dass pip installes während der parallelen Entwicklung vielleicht etwas merkwürdig sein würde (dh Pakete von Leuten aus verschiedenen Branchen würden sich vermischen, aber auf deterministische Weise), aber dass nach dem Zusammenführen alles aussortiert wurde. Abgesehen vom Vorhandensein einer exponierten Rebase oder Änderung funktionierte dies für die oben genannten Anforderungen recht gut.

Für den Fall, dass Sie sich wundern, haben wir uns entschieden, das r vor den Hash zu setzen, weil es komisch ist, wie Python-Verpackungen mit Buchstaben in Versionsnummern umgehen (dh ae ist kleiner als 0, was "1.3.10.a1234" <ergibt 1.3.10 <1.3.10.1234).


1
Übrigens, wie sind Sie mit dem Hühnerei-Problem umgegangen, den Git-Hash zu bestimmen, bevor Sie ihn einchecken? Hast du irgendeine Form von .gitignore oder einen anderen Trick benutzt?
kfmfe04

3
Habe ich nicht. Ich benutze den Hash erst, wenn das Paket fertig ist, was lange nach dem Einchecken liegt. Verschiedene Sprachen haben verschiedene Möglichkeiten, dies zu injizieren. Für Python verwende ich './setup.py egg_info -b ". $ {BUILD_VERSION}" sdist'. Für C und C ++ definiere ich zur Kompilierungszeit ein Makro mit 'CFLAGS = -D "$ {BUILD_VERSION}". Für Go definiere ich ein Symbol zur Link-Zeit mit 'go install -ldflags appmodule.BuildVersion "-X. $ {BUILD_VERSION}"'.
Jayson

1
Dies sollte die beste Antwort sein.
Alvinabad

sehr gute
antwort

9

Das mag ein bisschen übertrieben sein, aber ich werde Sie wissen lassen, wie wir es machen.

Wir verwenden eine Verzweigungsstruktur sehr ähnlich diesen .

Hudson baut auf unseren "Entwicklungs" -Zweigen auf und erhöht die Build-Nummern ab 0. Die Build-Nummer ist für jedes Projekt eindeutig und wird in der Versionskontrolle mit Tags versehen. Der Grund ist, dass Sie genau feststellen können, von welchem ​​Entwicklungszweig Build 42 stammt (jedes Projekt kann mehrere Entwicklungszweige gleichzeitig haben, da in jedem Projekt mehrere Teams an verschiedenen Aspekten des Projekts arbeiten können).

Wenn wir entscheiden, dass ein bestimmter Build für die Veröffentlichung geeignet ist, wird das Commit, das diesen Build ausgelöst hat, mit einer Versionsnummer versehen, die vom Marketing festgelegt wird. Dies bedeutet, dass die Entwickler-Teams sich nicht um die endgültige Versionsnummer kümmern und das Marketing frei ist, um Versionsnummern zu mischen, wie es passt. Die endgültige Versionsnummer und die Build-Nummer sind beide im freigegebenen Produkt enthalten.

Beispiel: 2.1.0 Build 1337

Dies bedeutet, dass Sie für eine bestimmte Produktversion feststellen können, welches Team zuletzt daran gearbeitet hat, und dass Sie git nach allen Commits abfragen können, die vor der Freigabe ausgeführt wurden, um ein Problem zu diagnostizieren, wenn dies erforderlich ist.


8

Versionen werden identifiziert, indem die SHA1-Hashes aller Dateien im gespeicherten Verzeichnisbaum zum Zeitpunkt des Eincheckens durchsucht werden. Dieser Hash wird zusammen mit den Hashes der übergeordneten Eincheckvorgänge gespeichert, damit der vollständige Verlauf gelesen werden kann.

Sehen Sie sich an, wie Sie 'git-describe' mithilfe von GIT-VERSION-GEN verwenden und wie Sie dies über Ihren Build-Prozess hinzufügen können, wenn Sie Ihr Release markieren.

Hier ist ein netter Blog, der ein Beispiel dafür gibt, wie Sie das bekommen, was Sie wollen:

http://cd34.com/blog/programming/using-git-to-generate-an-automatic-version-number/


0

Jon Purdy hat die richtige Idee. git flowerleichtert auch die eigentliche Verwaltung dieser Filialen und die Filialverwaltung ist ein Argument für den Umzug git.

Beginnen sie mit einem grundlegenden Überblick über beginnen git, da man aus dem kommt svn-zu-- gitPerspektive. Betrachten Sie im gitFolgenden:

master--...............-.....-..............-
        \             /     /              /
         ---develop---------............../
                            \            /
                             --feature---

Oben verzweigen Sie masterzu develop(mit gekennzeichnet \) und developzu einem featureZweig. Wir führen diese Zweige wieder zusammen (gekennzeichnet durch /), mit Commits ( -) entlang eines Zweigs. (Wenn es keine Festschreibung gibt, die Zusammenführung jedoch weit rechts liegt, gibt es .Indikatoren, die anzeigen, dass -die nächste Festschreibung die nächste ist.)

Leicht genug. Was ist, wenn wir einen Hotfix in unserer Hauptversion haben?

master--...............-.....-................-...........-.........-
        \             /     /                / \         /|        /
         \           /     /                /   -hotfix-- V       /
          ---develop---------............../..............-...----
                             \            / \             V   /
                              --feature---   --feature2...----

Oben developabgezweigt von master. Der in entdeckte Fehler masterwurde behoben, indem von verzweigt master, behoben und wieder zusammengeführt wurde master. Wir haben dann verschmolzen masterin developund dann developinfeature2 , die den neuen Code aus gewalztem hotfixin diesen Zweigen.

Wenn Sie feature2zurück zu zusammenführen develop, wird der Verlauf developmit dem eingeschlossen hotfix. Ebenso developwird es feature2mit dem neuen Code von zusammengeführt master, so dass das Zusammenführen von developwieder masterproblemlos möglich ist, da es auf dem Commit masterzu diesem Zeitpunkt basiert - als ob Sie von masterzu diesem Zeitpunkt abgezweigt wären .

Also hier ist eine andere Möglichkeit, das zu tun.

master--..........-........-
        \        /\       /
         ---1.0--  --1.1-- 

Ihre 1.0 Versionen erhalten tagged- 1.0.1, 1.0.2, 1.0.3und so weiter.

Hier ist ein Trick: Sie haben einen Fehler in 1.0 gefunden, der sich auf 1.1, 1.2 und 1.3 auswirkt. Wie geht's?

Sie verzweigen von Ihrem neuesten oder am frühesten gewarteten Release und reparieren es. Dann verschmelzen Sie Ihre neue hotfixNiederlassung in 1.3-und in 1.2, 1.1und 1.0. Verzweigen Sie nicht von jedem Zweig der Wartungsversion. nicht verschmelzen 1.0in masteroder verschmelzen masterwieder in 1.0. Nehmen Sie den einen hotfixZweig und fügen Sie ihn in alle Ihre Versionszweige ein. Wenn es Konflikte gibt, wird es Ihnen sagen; Überprüfen Sie Ihren Code, um sicherzustellen, dass die Änderungen korrekt sind ( git diffist Ihr Freund).

Jetzt wird diese spezifische Änderung überall angewendet. Die Linie ist verzweigt, aber es ist okay. Es ist kein Zufall. 1.3Kennzeichnen Sie den Kopf als 1.3.17, fügen Sie ihn in jedes Feature ein, von dem aus verzweigt wird 1.3, und fahren Sie fort.

Die git flowErweiterung unterstützt Sie bei der Verwaltung dieser Wartungs-, Feature- und Hotfix-Zweige. Sobald Sie den Workflow heruntergefahren haben, ist dies trivial und macht der Quellcodeverwaltung eine Menge Ärger.

Ich habe dies in Programmierteams gesehen, aber ich habe als Programmierer selbst nicht so intensiv gearbeitet, sodass ich mich immer noch um den täglichen Arbeitsablauf kümmere.


-6

Pro Git in Abschnitt 7.2 "Git-Attribute" im Erweiterungsteil "Keyword" enthält ein schönes Beispiel für die Verwendung von Smudge & Clean-Filtern zum Generieren von Keywords im RCS-Stil. Sie können dieselbe Technik zum Einbetten von Strings einer bestimmten Version in Code verwenden, der gemäß Ihren Regeln formatiert und berechnet wurde . Sie noch können verwendet werden git describeals Startpunkt, aber Sie haben die Möglichkeit, jede geeignetere Form zu transformieren und erhalten Sie von v2.5-14-feebdaed zum Beispiel sauber 2.5.14


9
-1 für das Ruinieren einer guten Antwort mit völlig unangebrachten Ad-Hominem-Angriffen.
Jörg W Mittag

9
Wer sagt, es waren Schwachköpfe , die dich abgewählt haben? Es könnten leicht Leute sein, die ein wenig Höflichkeit bevorzugen .
Mark Booth

Zu Ihrer Information, ich habe gerade die Antwort bearbeitet.
Keith Thompson

git describeGibt den Tag-Namen aus, es --longsei denn, er wurde übergeben oder seit dem letzten Tag wurden Commits ausgeführt, sodass er bereits vollständig sauber ist. Wenn Sie die Standardeinstellungen nicht geändert hätten, hätte es Ihnen genau das gegeben, was Sie wollten.
Strcat
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.