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?

Wenn Sie einen Make-basierten Build verwenden, können Sie dies in das Makefile einfügen:

GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"

(Sehen Mann git beschreiben für das, was die Schalter tun)

dann fügen Sie dies zu Ihren CFLAGS hinzu:

-DVERSION="$(GIT_VERSION)"

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:

#include "version.h"
const char * build_date = "2009-11-10 11:09";
const char * build_git_sha = "6b54ea36e92d4907aba8b3fade7f2d58a921b6cd";

Es gibt auch eine Header-Datei, die so aussieht:

#ifndef VERSION_H
#define VERSION_H
extern const char * build_date; /* 2009-11-10 11:09 */
extern const char * build_git_sha; /* 6b54ea36e92d4907aba8b3fade7f2d58a921b6cd */
#endif /* VERSION_H */

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:

/* version.c */
#include "version.h"
const char * build_git_sha = "ac5bffc90f0034df9e091a7b3aa12d150df26a0e";
const char * build_git_time = "Thu Dec  3 18:03:58 EST 2009";

Ich habe eine statische version.h-Datei, die so aussieht:

/*version.h*/
#ifndef VERSION_H_
#define VERSION_H_

extern const char * build_git_time;
extern const char * build_git_sha;


#endif /* VERSION_H_ */

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!

  • Ein Nachtrag … das funktioniert in Matlab:mathworks.com/matlabcentral/fileexchange/32864-get-git-info

    – AndyL

    13. September 11 um 17:19 Uhr


  • 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 ident Attributwas 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).

Wie kann ich meinen C Code dazu bringen seinen Git Versions Hash automatisch
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.

1643912890 812 Wie kann ich meinen C Code dazu bringen seinen Git Versions Hash automatisch
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

.

758650cookie-checkWie kann ich meinen C-Code dazu bringen, seinen Git-Versions-Hash automatisch auszudrucken?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy