Wie kann ich meinen C-Code dazu bringen, seinen Git-Versions-Hash automatisch auszudrucken?
Lesezeit: 9 Minuten
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 in einer .yaml-Datei zur späteren Analyse auf. Meine Experimente ändern sich von Tag zu Tag und ich muss oft den Code ändern. Um Revisionen nachzuverfolgen, verwende ich ein Git-Repository.
Ich möchte den Git-Revisions-Hash als Kommentar in meine .yaml-Datendateien aufnehmen können. Auf diese Weise konnte ich mir die .yaml-Datei ansehen und genau wissen, welcher Code verwendet wurde, um die in dieser Datei angezeigten Daten zu generieren. Gibt es eine einfache Möglichkeit, dies automatisch zu tun?
Dann können Sie einfach direkt im Programm auf die Version verweisen, als wäre es ein #define:
printf("Version: %sn", VERSION);
Standardmäßig druckt dies nur eine abgekürzte Git-Commit-ID, aber optional können Sie bestimmte Releases mit etwas wie dem folgenden markieren:
git tag -a v1.1 -m "Release v1.1"
dann wird es ausgedruckt:
Version: v1.1-2-g766d
Das heißt, 2 Commits nach v1.1, mit einer Git-Commit-ID, die mit „766d“ beginnt.
Wenn in Ihrem Baum nicht festgeschriebene Änderungen vorhanden sind, wird “-dirty” angehängt.
Es gibt keinen Abhängigkeitsscan, also müssen Sie einen expliziten machen make clean um die Aktualisierung der Version zu erzwingen. Das lässt sich aber lösen.
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.
+1 Persönlich ziehe ich es vor, dass das Makefile eine Header-Datei generiert, die enthält #define GIT_VERSION ... Anstatt es mit dem in die Befehlszeile zu schreiben -D Möglichkeit; es beseitigt das Abhängigkeitsproblem. Und warum der doppelte Unterstrich? Technisch gesehen ist das eine reservierte Kennung.
– Dan Formen
23. Mai 13 um 10:53 Uhr
Jedem das Seine – wie ich schon sagte, die Vorteile sind, dass es wenige bewegliche Teile hat und sie verständlich sind. Ich habe es bearbeitet, um die Unterstriche zu entfernen.
– ndyer
23. Mai ’13 um 16:53 Uhr
Es sollte hinzugefügt werden, dass man dies bei Verwendung von gengetopt direkt zu gengetopt im Makefile hinzufügen kann: gengetopt –set-version=$(GIT_VERSION)
– Trygve
12. Mai 15 um 7:13 Uhr
Die erste Anweisung sollte in Anführungszeichen gesetzt werden GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"funktioniert nicht ohne Anführungszeichen.
– AbelTom
25. Dezember 18 um 12:21 Uhr
In meinem Programm halte ich die Git-Versionsnummer und das Erstellungsdatum in einer separaten Datei namens version.cdie so aussieht:
Sowohl die Header-Datei als auch die C-Datei werden von einem Perl-Skript generiert, das wie folgt aussieht:
my $git_sha = `git rev-parse HEAD`;
$git_sha =~ s/s+//g;
# This contains all the build variables.
my %build;
$build{date} = make_date_time ();
$build{git_sha} = $git_sha;
hash_to_c_file ("version.c", %build, "build_");
Hier hash_to_c_file erledigt die ganze Arbeit des Schaffens version.c und version.h und make_date_time macht eine Zeichenfolge wie gezeigt.
Im Hauptprogramm habe ich eine Routine
#include "version.h"
// The name of this program.
const char * program_name = "magikruiser";
// The version of this program.
const char * version = "0.010";
/* Print an ID stamp for the program. */
static void _program_id_stamp (FILE * output)
{
fprintf (output, "%s / %s / %s / %sn",
program_name, version,
build_date, build_git_sha);
}
Ich kenne mich mit Git nicht so gut aus, daher würde ich mich über Kommentare freuen, wenn es einen besseren Weg gibt, dies zu tun.
Das Perl-Skript ist Teil des Build-Skripts, das ein “One-Step-Build” für alles ist.
– Benutzer181548
10. November 09 um 2:36 Uhr
Das ist soweit gut, aber denken Sie daran, dass es den Hash des letzten Commits auf dem Zweig meldet, nicht den Hash des Codes, der kompiliert wird. Wenn nicht festgeschriebene Änderungen vorhanden sind, werden diese nicht angezeigt.
– Phil Müller
10. November 09 um 3:52
git diff sucht standardmäßig nach Unterschieden zwischen Ihrem Arbeitsbereich und dem Index. Sie können auch versuchen, git diff –cached nach Unterschieden zwischen dem Index und HEAD zu suchen
– Karl
10. November 09 um 11:12 Uhr
All diese ‘const char *name = “value”;’ Konstrukte könnten sinnvollerweise in ‘const char name’ geändert werden[] = “value”;’, wodurch 4 Bytes pro Element auf einem 32-Bit-Computer und 8 Bytes pro Element auf einem 64-Bit-Computer eingespart werden. Zugegeben, in Zeiten von GB Hauptspeicher ist das kein großes Problem, aber es hilft alles. Beachten Sie, dass keiner der Codes, die die Namen verwenden, geändert werden muss.
– Jonathan Leffler
11. Nov. 09 um 7:40
Ich habe sie geändert, wie Sie vorgeschlagen haben. Die Größe meines Programms mit const char []: 319356 Byte (entfernt). Die Größe meines Programms mit const char *: 319324 Byte (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.
– Benutzer181548
11. November 09 um 7:53 Uhr
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-Rechnern hängen bleiben, auf denen awk von Natur aus mingw, aber nicht perl installiert ist. So funktioniert das.
Mein Makefile enthält eine Zeile, die git, date und awk aufruft, um eine AC-Datei zu erstellen:
$(MyLibs)/version.c: FORCE
$(GIT) rev-parse HEAD | awk ' BEGIN {print "#include "version.h""} {print "const char * build_git_sha = "" $$0"";"} END {}' > $(MyLibs)/version.c
date | awk 'BEGIN {} {print "const char * build_git_time = ""$$0"";"} END {} ' >> $(MyLibs)/version.c
Jedes Mal, wenn ich meinen Code kompiliere, generiert der awk-Befehl eine version.c-Datei, die so aussieht:
Der Rest meines Codes kann nun auf die Build-Zeit und den Git-Hash zugreifen, indem er einfach den version.h-Header einfügt. Um das Ganze zusammenzufassen, sage ich git, dass es version.c ignorieren soll, indem ich eine Zeile zu meiner .gitignore-Datei hinzufüge. Auf diese Weise gibt mir Git nicht ständig Merge-Konflikte. Hoffe das hilft!
das denke ich nicht FORCE ist eine gute Idee, da Makefile niemals zufrieden sein wird (jedes Mal, wenn Sie einen neuen Header erstellen). Stattdessen können Sie den relevanten Git-Dateien in der Formel einfach eine Abhängigkeit hinzufügen $(MyLibs)/version.c : .git/COMMIT_EDITMSG .git/HEAD . Datei COMMIT_EDITMSG ändert sich jedes Mal, wenn Sie ein Commit machen und HEAD ändert sich jedes Mal, wenn Sie den Verlauf durchsuchen, daher wird Ihre Datei jedes Mal aktualisiert, wenn sie relevant ist.
– Kamil S Jaron
7. April 17 um 9:56 Uhr
Ihr Programm kann berappen git describeentweder zur Laufzeit oder als Teil des Build-Prozesses.
Es gibt zwei Dinge, die Sie tun können:
Du kannst das schaffen Git einige Versionsinformationen für Sie in die Datei einzubetten.
Der einfachere Weg ist die Verwendung identAttributwas bedeutet setzen (zum Beispiel)
*.yaml ident
in .gitattributes Datei und $Id$ an der entsprechenden Stelle. Es würde automatisch auf die SHA-1-Kennung erweitert des Inhalts der Datei (Blob-ID): Dies ist NICHT die Dateiversion oder der letzte Commit.
Git unterstützt das Schlüsselwort $Id$ auf diese Weise, um zu vermeiden, dass Dateien berührt werden, die während des Zweigwechsels, des Zurückspulens des Zweigs usw. nicht geändert wurden. Wenn Sie wirklich möchten, dass Git die Commit-ID (Version) oder Beschreibung in die Datei einfügt, können Sie dies (missbrauchen) verwenden filter Attribut, indem Sie den Clean/Smudge-Filter verwenden, um ein Schlüsselwort (z. B. $Revision$) beim Auschecken zu erweitern und es für die Übergabe zu bereinigen.
Du kannst das schaffen Bauprozess um das für Sie zu tun, wie es der Linux-Kernel oder Git selbst tun.
Schauen Sie sich an GIT-VERSION-GEN Skript und seine Verwendung in Git Makefileoder zum Beispiel, wie dieses Makefile Versionsinformationen während der Generierung / Konfiguration von einbettet gitweb/gitweb.cgi Datei.
GIT-VERSION-GEN verwendet git beschreiben Versionsbeschreibung zu generieren. Es muss besser funktionieren, dass Sie Releases / Meilensteine Ihres Projekts markieren (mit signierten / kommentierten Tags).
Brian D. Foy
Wenn ich dies tun muss, verwende ich a Schildmögen RELEASE_1_23. Ich kann entscheiden, was das Tag sein kann, ohne den SHA-1 zu kennen. Ich bestätige dann Tag. Sie können dieses Tag beliebig in Ihrem Programm speichern.
PTT
Basierend auf der Antwort von njd27 verwende ich die a-Version mit Abhängigkeitsscanning 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.
# Get git commit version and date
GIT_VERSION := $(shell git --no-pager describe --tags --always --dirty)
GIT_DATE := $(firstword $(shell git --no-pager show --date=short --format="%ad" --name-only))
# recompile version.h dependants when GIT_VERSION changes, uses temporary file version~
.PHONY: force
version~: force
@echo '$(GIT_VERSION) $(GIT_DATE)' | cmp -s - $@ || echo '$(GIT_VERSION) $(GIT_DATE)' > $@
version.h: version~
@touch $@
@echo Git version $(GIT_VERSION) $(GIT_DATE)
Ich nehme an, Sie haben GIT_VERSION und GIT_DATE über CFLAGS übergeben, damit version.h sie verwenden kann. Cool!
– Jesse Chisholm
2. Juni 16 um 17:18 Uhr
.
7586500cookie-checkWie kann ich meinen C-Code dazu bringen, seinen Git-Versions-Hash automatisch auszudrucken?yes
Die Verwendung von Pre-Commit-Hooks (siehe book.git-scm.com/5_git_hooks.html ) wäre eine andere Möglichkeit, dies zu tun.
– Yktula
18. April 10 um 5:49 Uhr