¿Cómo puedo get mi código C para imprimir automáticamente su hash de versión Git?

¿Hay alguna manera fácil de escribir código C que pueda acceder a su hash de versión Git?

Escribí un software en C para recostackr datos científicos en un entorno de laboratorio. Mi código registra los datos que recoge en un file .yaml para su posterior análisis. Mis experimentos cambian día a día y a menudo tengo que modificar el código. Para realizar un seguimiento de las revisiones, utilizo un repository git.

Me gustaría poder include el hash de revisión de Git como un comentario en mis files de datos .yaml. De esa manera, podría mirar el file .yaml y saber exactamente qué código se utilizó para generar los datos que se muestran en ese file. ¿Hay una manera fácil de hacer esto automáticamente?

En mi progtwig, tengo el número de versión de git y la date de compilation en un file separado, llamado version.c , que se ve así:

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

También hay un file de encabezado, que se ve así:

 #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 */ 

Tanto el file de cabecera como el file C son generados por un script Perl que se ve así:

 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_"); 

Aquí hash_to_c_file hace todo el trabajo de crear version.c y version.h y make_date_time hace una cadena como se muestra.

En el progtwig principal, tengo una rutina

 #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 / %s\n", program_name, version, build_date, build_git_sha); } 

No estoy tan bien informado sobre git, por lo que me gustaría recibir comentarios si hay una mejor manera de hacerlo.

Si está utilizando una compilation basada en make, puede poner esto en el Makefile:

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

(Ver hombre git describe por lo que hacen los interruptores)

luego agrega esto a tu CFLAGS:

 -DVERSION=\"$(GIT_VERSION)\" 

Entonces puede simplemente hacer reference a la versión directamente en el progtwig como si fuera un #define:

 printf("Version: %s\n", VERSION); 

De forma pnetworkingeterminada, esto solo imprime un ID de confirmación de git abreviado, pero opcionalmente puede labelr lanzamientos particulares con algo como:

 git tag -a v1.1 -m "Release v1.1" 

entonces se imprimirá:

 Version: v1.1-2-g766d 

lo que significa que 2 commits pasado v1.1, con un ID de commit git que comienza con "766d".

Si hay cambios no confirmados en su tree, se agregará "-dirty".

No hay escaneo de dependencies, por lo que debe hacer una make clean explícita para forzar la actualización de la versión. Esto puede ser resuelto sin embargo.

Las ventajas son que es simple y no requiere ninguna dependencia de compilation adicional como perl o awk. He usado este enfoque con GNU automake y con comstackciones Android NDK.

Su progtwig puede pagar para git describe , ya sea en time de ejecución o como parte del process de compilation.

Terminé usando algo muy similar a la respuesta de @Kinopiko, pero usé awk en lugar de Perl. Esto es útil si está atascado en las máquinas de Windows que tienen awk instalado por naturaleza de mingw, pero no perl. Así es como funciona.

Mi file MAKE tiene una línea que invoca git, date y awk para crear un file CA:

 $(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 

Cada vez que compilo mi código, el command awk genera un file version.c que se ve así:

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

Tengo un file static version.h que se ve así:

 /*version.h*/ #ifndef VERSION_H_ #define VERSION_H_ extern const char * build_git_time; extern const char * build_git_sha; #endif /* VERSION_H_ */ 

El rest de mi código ahora puede acceder al time de compilation y al hash git simplemente incluyendo el encabezado version.h. Para concluir todo, le digo a git que ignore la versión.c agregando una línea a mi file .gitignore. De esta manera, git no me está dando constantemente conflictos de fusión. ¡Espero que esto ayude!

Hay dos cosas que puedes hacer:

  • Puede hacer que Git incruste información de la versión en el file por usted.

    La forma más simple es usar el atributo ident , que significa poner (por ejemplo)

     *.yaml ident 

    en el file .gitattributes , y $Id$ en el lugar apropiado. Se expandiría automáticamente al identificador SHA-1 de los contenidos del file (id de blob): NO es la versión de file o la última confirmación.

    Git admite $ Id $ keyword de esta forma para evitar tocar files que no se cambiaron durante el cambio de twig, la twig de rebobinado, etc. Si realmente desea que Git ponga el identificador o la descripción del commit (versión) en el file, puede (ab) usar filter atributo, utilizando el filter limpiar / difuminar para expandir algunas palabras key (p. ej., $ Revision $) al finalizar la compra, y limpiarlo para la confirmación.

  • Puede hacer que el process de compilation lo haga por usted, como lo hace Linux Kernel o Git.

    Eche un vistazo al script de GIT-VERSION-GEN y su uso en Git Makefile , o por ejemplo, cómo este Makefile incorpora información de versión durante la generación / configuration del file gitweb/gitweb.cgi .

    GIT-VERSION-GEN utiliza git describe para generar la descripción de la versión. Debe funcionar mejor que etiquete (utilizando tags firmadas / anotadas) lanzamientos / hitos de su proyecto.

Cuando necesito hacer esto, uso una label , como RELEASE_1_23 . Puedo decidir cuál puede ser la label sin conocer el SHA-1. Me comprometo luego label. Puede almacenar esa label en su progtwig de todos modos que desee.

De acuerdo con la respuesta de njd27, estoy usando la versión a con análisis de dependencia, en combinación con un file version.h con valores pnetworkingeterminados para cuando el código se construye de una manera diferente. Todos los files que incluyen version.h serán reconstruidos.

También incluye la date de revisión como una definición separada.

 # 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) 

También uso git para rastrear cambios en mi código científico. No quería usar un progtwig externo porque limita la portabilidad del código (si alguien quisiera hacer cambios en MSVS, por ejemplo).

mi solución fue usar solo la twig principal para los cálculos y hacer que __DATE__ el time de compilation usando las macros del preprocesador __DATE__ y __TIME__ . de esa manera puedo verificarlo con git log y ver qué versión estoy usando. ref: http://gcc.gnu.org/onlinedocs/cpp/Standard-Pnetworkingefined-Macros.html

Otra forma elegante de resolver el problema es include git log en el ejecutable. crea un file object del logging git e inclúyalo en el código. esta vez, el único progtwig externo que usa es objcopy pero hay less encoding. ref: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 y datos embeddeds en un progtwig C ++

Lo que debe hacer es generar un file de encabezado (por ejemplo, usando echo desde la línea cmd) algo como esto:

 #define GIT_HASH \ "098709a0b098c098d0e" 

Para generarlo, utiliza algo como esto:

 echo #define GIT_HASH \ > file.h echo " > file.h echo git status <whatever cmd to get the hash> > file.h echo " > file.h 

Puede que necesite jugar con las comillas y las barras diagonales un poco para que se compile, pero se entiende la idea.

Puedes ver cómo lo hice para memcached en la confirmación original .

Básicamente, marque ocasionalmente y asegúrese de que lo que entrega proviene de make dist o similar.

Otra variación más basada en Makefile y shell

 GIT_COMMIT_FILE=git_commit_filename.h $(GIT_COMMIT_FILE): phony $(eval GIT_COMMIT_SHA=$(shell git describe --abbrev=6 --always 2>/dev/null || echo 'Error')) @echo SHA=$(GIT_COMMIT_SHA) echo -n "static const char *GIT_COMMIT_SHA = \"$(GIT_COMMIT_SHA)\";" > $(GIT_COMMIT_FILE) 

El file git_commit_filename.h terminará con una sola línea que contiene static const char * GIT_COMMIT_SHA = "";

Desde https://gist.github.com/larytet/898ec8814dd6b3ceee65532a9916d406