Search code examples
cgitversion-controlworkflow

How can I get my C code to automatically print out its Git version hash?


Is there an easy way to write C code that can access its Git version hash?

I wrote software in C to collect scientific data in a laboratory setting. My code records the data it collects in a .yaml file for later analysis. My experiments change from day-to-day and I often have to modify the code. To keep track of revisions, I use a git repository.

I would like to be able to include the Git revision hash as a comment in my .yaml data files. That way, I could look at the .yaml file and know exactly what code was used to generate the data shown in that file. Is there an easy way to do this automatically?


Solution

  • In my program, I hold the git version number and the date of the build in a separate file, called version.c, which looks like this:

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

    There is also a header file, which looks like this:

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

    Both the header file and the C file are generated by a Perl script which looks like this:

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

    Here hash_to_c_file does all the work of creating version.c and version.h and make_date_time makes a string as shown.

    In the main program, I have a 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 / %s\n",
                 program_name, version,
                 build_date, build_git_sha);
    }
    

    I'm not that knowledgeable about git, so I'd welcome comments if there is a better way to do this.