在Git中,如何将当前提交哈希写入同一提交中的文件


130

我试图在这里用Git钩子做一些花哨的东西,但我真的不知道该怎么做(或者是否有可能)。

我需要做的是:在每个提交中,我都想获取其哈希值,然后使用此哈希值更新提交中的文件。

有任何想法吗?


12
基本上,我有一个Web应用程序,并且我想将该应用程序的已安装版本与该版本相关联的确切提交相关联。我最初的想法是使用提交哈希更新某种about.html文件。但是在研究了git的对象模型后,我意识到这是不可能的= /
Felipe Kamakura 2010年

29
这是一个非常实际的问题。我也遇到了!
李栋

7
对于我来说,我希望程序将这样的消息写入日志:“ myprog启动,v.56c6bb2”。这样,如果有人提交了一个错误并发送了日志文件给我,我可以确切地知道我的程序正在运行哪个版本。
爱德华·福克

5
@Jefromi,实际用例实际上很常见,很容易打动初学者。将真实版本以某种方式“压印”到基准文件中是一个基本需求,并且要弄清楚为什么这是个错误的主意还差很远,例如,因为这几乎是手动版本控制黑客的唯一选择。(请记住,初学者。)此外,许多项目根本没有任何构建/安装/部署步骤,可以将版本抓取并标记到活动文件中。无论如何,即使在那些情况下,结帐后钩子也可以帮助您代替预先提交。
Sz。

这是不可能的!如果您能做到这一点,就破坏了SHA-1哈希算法... ericsink.com/vcbe/html/cryptographic_hashes.html
betontalpfa

Answers:


81

我建议您执行与您的想法类似的操作:将SHA1放在未跟踪的文件中,该文件是在构建/安装/部署过程中生成的。这显然很容易做到(git rev-parse HEAD > filename或者也许git describe [--tags] > filename),并且避免做任何疯狂的事情,例如以与git跟踪的文件不同的文件结尾。

然后,您的代码可以在需要版本号时引用该文件,或者构建过程可以将信息合并到最终产品中。后者实际上是git本身如何获取其版本号的方法-构建过程将版本号从存储库中提取出来,然后将其构建到可执行文件中。


3
有人可以进一步逐步说明如何执行此操作吗?或至少在正确的方向上轻推?
乔尔·沃舍姆

1
@Joel怎么办?我提到了如何将散列放入文件中。其余大概是关于您的构建过程的?如果您要询问那一部分,也许是一个新问题。
卡斯卡贝尔2014年

1
就我而言,我向我的Makefile添加了一条规则,该规则在每次构建时都会生成一个“ gitversion.h”文件。参见stackoverflow.com/a/38087913/338479
Edward Falk 2016年

1
您也许可以使用“ git-checkout”挂钩自动执行此操作。问题是这些挂钩必须手动安装。
爱德华·福克

14

编写当前的提交哈希是不可能的:如果您要预先计算将来的提交哈希,则在修改任何文件后它将立即更改。

但是,有三种选择:

  1. 使用脚本增加“ commit id”并将其包含在某处。丑陋
  2. .gitignore将要存储哈希值的文件。不太方便
  3. 在中pre-commit,存储先前的提交哈希:)在99.99%的情况下,您无需修改​​/插入提交,因此,它将起作用。在最坏的情况下,您仍然可以识别源版本。

我正在研究一个钩子脚本,它将在“完成时”发布到此处,但是仍然比Duke Nukem Forever发行更早了:))

更新:代码.git/hooks/pre-commit

#!/usr/bin/env bash
set -e

#=== 'prev-commit' solution by o_O Tync
#commit_hash=$(git rev-parse --verify HEAD)
commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
commit_hash=$(echo "$commit" | head -1)
commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300

branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation

# Write it
echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py

现在,我们唯一需要的是一个将对转换prev_commit,branch为实际提交哈希的工具:)

我不知道这种方法是否可以区分合并提交。会很快检查出来


13

有人将我指向ident的“ man gitattributes”部分,内容如下:

身份

为路径设置属性ident时,git用$ Id:替换blob对象中的$ Id $,后跟40个字符的十六进制blob对象名,并在结帐时后跟一个美元符号$。在工作树文件中,任何以$ Id:开头并以$结尾的字节序列在检入时都将替换为$ Id $。

如果您考虑一下,这也是CVS,Subversion等所做的。如果查看存储库,将会看到存储库中的文件始终包含例如$ Id $。它从不包含任何扩展。仅在结帐时才扩展文本。


8
ident是文件本身的哈希值,而不是提交的草率。来自git-scm.com/book/en/…:“但是,该结果用途有限。如果您在CVS或Subversion中使用了关键字替换,则可以添加一个日期戳-SHA并没有那么大的帮助,因为它是相当随机的,您无法确定一个SHA是否比另一个SHA更旧或更新。” filter需要工作,但可以将提交信息放入(或移出)文件。
扎克·杨

11

这可以通过使用gitattributes中filter属性来实现。您需要提供一个插入提交ID的命令,以及一个删除提交ID的命令,以使插入的文件不会仅仅因为提交ID而改变。smudgeclean

因此,提交ID永远不会存储在文件的Blob中。它只是在您的工作副本中扩展了。(实际上,将提交ID插入到Blob中将成为无限递归的任务。)克隆此树的任何人都需要为自己设置属性。


7
不可能的任务,不是递归任务。提交哈希取决于树哈希,后者取决于文件哈希,后者取决于文件内容。您必须获得自我一致性。除非您为SHA-1哈希找到一种[广义]不动点
JakubNarębski2010年

1
@ Jakub,git中是否有某种技巧可以创建跟踪文件,而不会修改生成的哈希?也许可以使用某种方法来覆盖其哈希值。那将是一个解决方案:)
kolypto 2010年

@o_O Tync:不可能。更改的文件意味着更改的(文件的)哈希值-这是设计使然,并通过哈希函数的定义。
JakubNarębski2011年

2
这是一个很好的解决方案,但请记住,这涉及到在克隆存储库时必须手动安装的挂钩。
Edward Falk

7

在提交框之外思考!

将其弹出到文件挂钩/检出后

#!/bin/sh
git describe --all --long > config/git-commit-version.txt

您可以在任何使用该版本的地方使用该版本。


3

我认为您实际上并不想要这样做,因为当提交中的文件更改时,提交的哈希也将更改。


1

让我探讨一下为什么使用git内部函数这是一个具有挑战性的问题。您可以通过以下方式获取当前提交的sha1

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

本质上,您对所返回的消息运行sha1校验和git cat-file commit HEAD。当您检查此消息时,有两件事立即跳出一个问题。一个是树sha1,第二个是提交时间。

现在,可以通过更改消息并猜测在特定时间进行提交或安排提交所花费的时间来轻松地处理提交时间。真正的问题是树sha1,您可以从那里得到它git ls-tree $(git write-tree) | git mktree。本质上,您正在对来自ls-tree的消息进行sha1校验和,该消息是所有文件及其sha1校验和的列表。

因此,您的提交sha1校验和取决于您的树sha1校验和,它直接取决于文件sha1校验和,该文件完成循环并取决于提交sha1。因此,您对自己可用的技术有一个循环性的问题。

如果校验和的安全性较低,则可以通过蛮力将文件的校验和写入文件本身。但是,我不知道用sha1完成任何任务的工作。这并非不可能,但就我们目前的理解而言,这几乎是不可能的(但谁知道几年后这将是微不足道的)。但是,由于您必须将(blob)校验和的(tree)校验和的(commit)校验和写入文件中,因此,这甚至更加难以实现。


有没有一种方法可以提交文件,然后进行检出并在每个源代码文件的开头放置最新的提交哈希作为注释?然后从中构建并运行?
John Wooten
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.