Gibt es eine einfache Möglichkeit, C-Code zu schreiben, der auf den Hash der Git-Version zugreifen kann?
Ich habe Software in C geschrieben, um wissenschaftliche Daten in einer Laborumgebung zu sammeln. Mein Code zeichnet die gesammelten Daten zur späteren Analyse in einer .yaml-Datei auf. Meine Experimente ändern sich von Tag zu Tag und ich muss oft den Code ändern. Um Revisionen zu verfolgen, verwende ich ein Git-Repository.
Ich möchte in der Lage sein, den Git-Revisions-Hash als Kommentar in meine .yaml-Datendateien aufzunehmen. Auf diese Weise konnte ich mir die .yaml-Datei ansehen und genau wissen, mit welchem Code die in dieser Datei angezeigten Daten generiert wurden. Gibt es eine einfache Möglichkeit, dies automatisch zu tun?
c
git
version-control
workflow
AndyL
quelle
quelle
Antworten:
In meinem Programm halte ich die Git-Versionsnummer und das Datum des Builds in einer separaten Datei namens "
version.c
, die folgendermaßen aussieht:Es gibt auch eine Header-Datei, die so aussieht:
Sowohl die Header-Datei als auch die C-Datei werden von einem Perl-Skript generiert, das folgendermaßen aussieht:
Hier
hash_to_c_file
erledigt man die ganze Arbeit des Erstellensversion.c
undversion.h
undmake_date_time
macht einen String wie gezeigt.Im Hauptprogramm habe ich eine Routine
Ich kenne mich mit Git nicht so gut aus, daher würde ich Kommentare begrüßen, wenn es einen besseren Weg gibt, dies zu tun.
quelle
const char []
: 319356 Bytes (gestrippt). Die Größe meines Programms mitconst char *
: 319324 Bytes (entfernt). Ihre Idee scheint also keine Bytes zu sparen, sondern erhöht die Gesamtzahl um 32. Ich habe keine Ahnung warum. In der ursprünglichen "version.c" gibt es drei Zeichenfolgen, aber eine wurde in der obigen Antwort weggelassen. Wenn Sie sich die erste Bearbeitung ansehen, ist sie immer noch da.Wenn Sie einen make-basierten Build verwenden, können Sie diesen in das Makefile einfügen:
(Siehe man git beschreiben, was die Schalter tun)
Fügen Sie dies dann Ihren CFLAGS hinzu:
Dann können Sie einfach direkt im Programm auf die Version verweisen, als wäre es ein #define:
Standardmäßig wird nur eine abgekürzte Git-Commit-ID gedruckt. Optional können Sie jedoch bestimmte Releases mit folgenden Tags versehen:
dann wird es ausgedruckt:
Das heißt, 2 Commits nach Version 1.1, wobei eine Git-Commit-ID mit "766d" beginnt.
Wenn in Ihrem Baum nicht festgeschriebene Änderungen vorhanden sind, wird "-dirty" angehängt.
Es gibt kein Scannen von Abhängigkeiten, daher müssen Sie eine explizite
make clean
Aktion ausführen, um die Aktualisierung der Version zu erzwingen. Dies kann jedoch gelöst werden .Die Vorteile sind, dass es einfach ist und keine zusätzlichen Build-Abhängigkeiten wie Perl oder Awk erfordert. Ich habe diesen Ansatz mit GNU Automake und mit Android NDK Builds verwendet.
quelle
#define GIT_VERSION ...
anstatt sie mit der-D
Option in die Befehlszeile zu setzen . Es beseitigt das Abhängigkeitsproblem. Auch warum der doppelte Unterstrich? Technisch gesehen ist das eine reservierte Kennung.GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"
und funktioniert nicht ohne Anführungszeichen.Am Ende habe ich etwas verwendet, das der Antwort von @ Kinopiko sehr ähnlich ist, aber ich habe awk anstelle von perl verwendet. Dies ist nützlich, wenn Sie auf Windows-Computern stecken, auf denen awk von Natur aus mingw installiert ist, jedoch nicht perl. So funktioniert das.
Mein Makefile enthält eine Zeile, die git, date und awk aufruft, um eine AC-Datei zu erstellen:
Jedes Mal, wenn ich meinen Code kompiliere, generiert der Befehl awk eine version.c-Datei, die folgendermaßen aussieht:
Ich habe eine statische version.h-Datei, die so aussieht:
Der Rest meines Codes kann jetzt auf die Build-Zeit und den Git-Hash zugreifen, indem einfach der Header version.h eingefügt wird. Zum Abschluss fordere ich git auf, version.c zu ignorieren, indem ich meiner .gitignore-Datei eine Zeile hinzufüge. Auf diese Weise gibt mir Git nicht ständig Zusammenführungskonflikte. Hoffe das hilft!
quelle
FORCE
eine gute Idee, da Makefile niemals zufrieden sein wird (jedes Mal, wenn Sie einen neuen Header erstellen). Stattdessen können Sie einfach Abhängigkeiten zu relevanten Git-Dateien in der Formel hinzufügen$(MyLibs)/version.c : .git/COMMIT_EDITMSG .git/HEAD
. Die DateiCOMMIT_EDITMSG
ändert sich jedes Mal, wenn Sie einen Commit durchführen, undHEAD
jedes Mal, wenn Sie den Verlauf durchsuchen. Daher wird Ihre Datei jedes Mal aktualisiert, wenn dies relevant ist.Ihr Programm kann
git describe
entweder zur Laufzeit oder als Teil des Erstellungsprozesses ausgeführt werden.quelle
git help describe
: "Das neueste Tag anzeigen, das über ein Commit erreichbar ist" - das ist nicht das, wonach die Frage fragt. Ich stimme jedoch dem Rest Ihrer Antwort zu. Um korrekt zu sein, sollte der Befehl lautengit rev-parse HEAD
.git describe
wird in den meisten anderen Projekten verwendet, da es auch lesbare Tag-Informationen enthält. Wenn Sie sich nicht genau in einem Tag befinden, werden die Anzahl der Commits seit dem nächsten Tag und der abgekürzte Revisions-Hash angehängt.Sie können zwei Dinge tun:
Sie können Git dazu bringen, einige Versionsinformationen für Sie in die Datei einzubetten.
Der einfachere Weg ist die Verwendung von
ident
Attributen , dh Putten (zum Beispiel).in der
.gitattributes
Datei und$Id$
an der entsprechenden Stelle. Es wird automatisch auf die SHA-1-Kennung des Dateiinhalts (Blob-ID) erweitert: Dies ist NICHT die Dateiversion oder das letzte Commit.Git unterstützt auf diese Weise das Schlüsselwort $ Id $, um zu vermeiden, dass Dateien berührt werden, die beim Wechseln der Verzweigung, Zurückspulen der Verzweigung usw. nicht geändert wurden
filter
Attribut: Verwenden Sie den Clean / Smudge-Filter, um ein Schlüsselwort (z. B. $ Revision $) beim Auschecken zu erweitern und es für das Festschreiben zu bereinigen.Sie können einen Build-Prozess erstellen, der dies für Sie erledigt, wie dies der Linux-Kernel oder Git selbst tun.
Sehen Sie sich das GIT-VERSION-GEN- Skript und seine Verwendung in Git Makefile an oder beispielsweise, wie dieses Makefile Versionsinformationen während der Generierung / Konfiguration von
gitweb/gitweb.cgi
Dateien einbettet .GIT-VERSION-GEN verwendet git description, um eine Versionsbeschreibung zu generieren. Es muss besser funktionieren, wenn Sie Releases / Meilensteine Ihres Projekts (mit signierten / kommentierten Tags) markieren.
quelle
Wenn ich das tun muss, benutze ich ein Tag wie
RELEASE_1_23
. Ich kann entscheiden, was das Tag sein kann, ohne den SHA-1 zu kennen. Ich verpflichte mich dann tag. Sie können dieses Tag in Ihrem Programm speichern, wie Sie möchten.quelle
Basierend auf der Antwort von njd27 verwende ich eine Version mit Abhängigkeitsscan in Kombination mit einer version.h-Datei mit Standardwerten, wenn der Code auf andere Weise erstellt wird. Alle Dateien, die version.h enthalten, werden neu erstellt.
Es enthält auch das Überarbeitungsdatum als separate Definition.
quelle
Ich benutze git auch, um Änderungen in meinem wissenschaftlichen Code zu verfolgen. Ich wollte kein externes Programm verwenden, da es die Portabilität des Codes einschränkt (wenn jemand beispielsweise Änderungen an MSVS vornehmen möchte).
Meine Lösung bestand darin, nur den Hauptzweig für die Berechnungen zu verwenden und die Erstellungszeit mithilfe von Präprozessor-Makros
__DATE__
und auszugeben__TIME__
. Auf diese Weise kann ich es mit Git Log überprüfen und sehen, welche Version ich verwende. Ref: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.htmlEine andere elegante Möglichkeit, das Problem zu lösen, besteht darin, das Git-Protokoll in die ausführbare Datei aufzunehmen. Erstellen Sie eine Objektdatei aus dem Git-Protokoll und fügen Sie sie in den Code ein. Dieses Mal ist das einzige externe Programm, das Sie verwenden, objcopy, aber es gibt weniger Codierung. ref: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 und Daten in ein C ++ - Programm einbetten
quelle
Was Sie tun müssen, ist eine Header-Datei zu generieren (z. B. mit Echo aus der cmd-Zeile).
Verwenden Sie Folgendes, um es zu generieren:
Möglicherweise müssen Sie ein wenig mit den Anführungszeichen und Backslashes spielen, damit sie kompiliert werden können, aber Sie haben die Idee.
quelle
--assume-unchanged
git update-index --assume-unchanged
Noch eine Variation basierend auf Makefile und Shell
Die Datei git_commit_filename.h enthält eine einzelne Zeile mit dem statischen const char * GIT_COMMIT_SHA = "";
Von https://gist.github.com/larytet/898ec8814dd6b3ceee65532a9916d406
quelle
Dies ist eine Lösung für CMake-Projekte, die unter Windows und Linux funktioniert, ohne dass andere Programme (z. B. Skriptsprachen) installiert werden müssen.
Der Git-Hash wird von einem Skript in eine .h-Datei geschrieben. Dies ist ein Bash-Skript beim Kompilieren unter Linux oder ein Windows-Batch-Skript beim Kompilieren unter Windows. Eine if-Klausel in CMakeLists.txt wählt das Skript aus, das der Plattform entspricht Code wird am kompiliert.
Die folgenden 2 Skripte werden im selben Verzeichnis wie CMakeLists.txt gespeichert:
get_git_hash.sh:
get_git_hash.cmd:
In CMakeLists.txt werden die folgenden Zeilen hinzugefügt
In dem Code ist die generierte Datei enthalten,
#include <my_project/githash.h>
und der Git-Hash kann aufstd::cout << "Software version: " << kGitHash << std::endl;
ähnliche Weise auf das Terminal gedruckt oder in eine Yaml-Datei (oder eine beliebige Datei) geschrieben werden.quelle
Sie können sehen, wie ich es für memcached im ursprünglichen Commit gemacht habe .
Markieren Sie im Grunde gelegentlich und stellen Sie sicher, dass das, was Sie liefern, von
make dist
oder ähnlichem stammt.quelle