如何让我的C代码自动打印出它的Git版本哈希?

And*_*dyL 76 c git version-control workflow

有没有一种简单的方法来编写可以访问其Git版本哈希的C代码?

我在C中编写软件以在实验室环境中收集科学数据.我的代码将它收集的数据记录在.yaml文件中以供以后分析.我的实验每天都在变化,我经常需要修改代码.为了跟踪修订,我使用了一个git存储库.

我希望能够在我的.yaml数据文件中包含Git版本哈希作为注释.这样,我可以查看.yaml文件并确切地知道用于生成该文件中显示的数据的代码.有一种简单的方法可以自动执行此操作吗?

ndy*_*yer 148

如果您使用的是基于make的构建,则可以将其放在Makefile中:

GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"
Run Code Online (Sandbox Code Playgroud)

(参见man git describe,了解开关的用途)

然后将其添加到您的CFLAGS:

-DVERSION=\"$(GIT_VERSION)\"
Run Code Online (Sandbox Code Playgroud)

然后你可以直接在程序中引用该版本,就像它是#define一样:

printf("Version: %s\n", VERSION);
Run Code Online (Sandbox Code Playgroud)

默认情况下,这只会打印一个缩写的git commit id,但是您可以选择使用以下内容标记特定版本:

git tag -a v1.1 -m "Release v1.1"
Run Code Online (Sandbox Code Playgroud)

然后会打印出来:

Version: v1.1-2-g766d
Run Code Online (Sandbox Code Playgroud)

这意味着,2提交过v1.1,git commit id以"766d"开头.

如果树中存在未提交的更改,则会附加"-dirty".

没有依赖项扫描,因此您必须明确make clean强制更新版本.然而,这可以解决.

优点是它很简单,不需要任何额外的构建依赖,如perl或awk.我已经在GNU automake和Android NDK版本中使用了这种方法.

  • 每个都是他们自己 - 正如我所说的优点是它有很少的活动部件,他们是可以理解的.我编辑了它以删除下划线. (8认同)
  • +1就个人而言,我更喜欢让makefile生成一个包含`#define GIT_VERSION ...`的头文件,而不是使用`-D`选项将它放在命令行中; 它消除了依赖性问题.另外,为什么双下划线?从技术上讲,这是一个保留的标识符. (4认同)

小智 38

在我的程序中,我将git版本号和构建日期保存在一个名为的单独文件中,version.c如下所示:

#include "version.h"
const char * build_date = "2009-11-10 11:09";
const char * build_git_sha = "6b54ea36e92d4907aba8b3fade7f2d58a921b6cd";
Run Code Online (Sandbox Code Playgroud)

还有一个头文件,如下所示:

#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 */
Run Code Online (Sandbox Code Playgroud)

头文件和C文件都是由Perl脚本生成的,如下所示:

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_");
Run Code Online (Sandbox Code Playgroud)

这里hash_to_c_file确实创造了所有的工作version.c,并version.hmake_date_time使一个字符串,如图所示.

在主程序中,我有一个例程

#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);
}
Run Code Online (Sandbox Code Playgroud)

我对git知之甚少,所以如果有更好的方法,我会欢迎评论.

  • 这是好的,但请记住,它将报告分支上最新提交的哈希值,而不是正在编译的代码的哈希值.如果存在未提交的更改,则这些更改将不明显. (12认同)
  • 所有那些'const char*name ="value";' 构造可以合理地改为'const char name [] ="value";',它在32位机器上每个项目节省4个字节,在64位机器上每个项目节省8个字节.当然,在GB的主要内存中,这不是一个大问题,但这一切都有帮助.请注意,使用名称的代码都不需要更改. (6认同)

And*_*dyL 11

我最终使用的东西与@ Kinopiko的答案非常相似,但我用的是awk而不是perl.如果你坚持使用mingw性质而不是perl安装了awk的windows机器,这是很有用的.这是它的工作原理.

我的makefile中有一行调用git,date和awk来创建ac文件:

$(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 
Run Code Online (Sandbox Code Playgroud)

每次编译我的代码时,awk命令都会生成一个如下所示的version.c文件:

/* version.c */
#include "version.h"
const char * build_git_sha = "ac5bffc90f0034df9e091a7b3aa12d150df26a0e";
const char * build_git_time = "Thu Dec  3 18:03:58 EST 2009";
Run Code Online (Sandbox Code Playgroud)

我有一个静态version.h文件,如下所示:

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

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


#endif /* VERSION_H_ */
Run Code Online (Sandbox Code Playgroud)

我的其余代码现在可以通过简单地包含version.h头来访问构建时和git哈希.为了将它全部包装起来,我告诉git通过在我的.gitignore文件中添加一行来忽略version.c. 这样git不会经常给我合并冲突.希望这可以帮助!


bdo*_*lan 9

您的程序可以git describe在运行时或作为构建过程的一部分进行shell .

  • @mikem,`git describe`是大多数其他项目使用的,因为它也包含人类可读的标签信息.如果您不完全在标记上,它会附加自最近标记以来的提交数量以及缩写版本哈希值. (5认同)
  • 来自`git help describe`:"显示可以从提交中访问的最新标记" - 这不是问题所要求的.不过,我同意你的其余答案.为了正确,命令应该是`git rev-parse HEAD`. (4认同)

Jak*_*ski 7

你可以做两件事:

  • 您可以让Git为您嵌入一​​些版本信息.

    更简单的方法是使用ident 属性,这意味着放(例如)

    *.yaml    ident
    
    Run Code Online (Sandbox Code Playgroud)

    .gitattributes文件中,并$Id$在适当的地方.它将自动扩展为文件内容的 SHA-1标识符(blob id):这不是文件版本,也不是最后一次提交.

    Git以这种方式支持$ Id $关键字,以避免触摸在分支切换,倒带分支等期间未更改的文件.如果您真的希望Git将提交(版本)标识符或描述放在文件中,您可以(ab)使用filter属性,使用clean/smudge过滤器在结帐时展开一些关键字(例如$ Revision $),并清理它以进行提交.

  • 你可以让构建过程为你做这件事,比如Linux内核或Git本身.

    看一下GIT-VERSION-GEN脚本及其在Git Makefile中的用法,或者例如这个Makefile如何在生成/配置gitweb/gitweb.cgi文件期间嵌入版本信息.

    GIT-VERSION-GEN使用git describe生成版本描述.它需要更好地标记(使用签名/注释标签)项目的发布/里程碑.