Git:获取工作树当前状态的哈希值?

14

我希望确保我的可执行文件使用最新版本的代码构建。

例如,我可以在编译时获取当前git提交并将其嵌入到可执行文件中;然后当运行可执行文件时,它会将其与当前git提交进行比较,如果不匹配,则会提示代码已被修改且过时。

然而,有时候我会在未提交更改的情况下重新编译代码。这种方法就不起作用了,因为它只考虑提交的更改。

是否有一种方便的方法,可以使用git或其他方式以编程方式获取当前提交的哈希值加上工作目录的状态?

此实践是否有名称?


1
为什么你不记得在编译之前提交?你应该能够在脚本中以编程方式检查工作副本是否已被更改或污染,然后再开始编译。 - user456814
我正在使用这个来在JavaScript服务工作者中生成缓存名称。在这种情况下,没有编译步骤。我可以让Web服务器动态生成一个JavaScript文件,其中包含基于Web应用程序哈希的缓存名称。在开发过程中,将未检入的本地更改包含在缓存名称中是很方便的。 - Stephen Ostermiller
2个回答

6

可以在当前工作树中创建和存储大多数更改,包括所有已暂存、未暂存和未跟踪的文件,并遵守 .gitignore。大致上,需要执行以下操作:

#!/bin/sh
{   git diff-index --name-only HEAD
    git ls-files -o --exclude-standard
} \
| while read path; do
    test -f "$path" && printf "100644 blob %s\t$path\n" $(git hash-object -w "$path");
    test -d "$path" && printf "160000 commit %s\t$path\n" $(cd "$path"; git rev-parse HEAD);
done | sed 's,/,\\,g' | git mktree --missing

首先,第一个 diff 列出了所有与 HEAD 不同的已跟踪文件。

然后,我们找到未跟踪的文件,但排除了被忽略的文件。

接下来,我们将这两个命令的输出传递到一个循环中,该循环构建所有文件的 git mktree 输入。

由于 git mktree 不会递归构建树形结构,因此我们需要通过 sed 处理其输出。但是,实际路径并不重要,因为我们只想要哈希码,而没有存储任何实际内容以供检索。

最后,我们将这个 ls-tree 格式化的输出传递给 mktree,它会构建指定的树形结构并将其存储在 Git 中,并将哈希码输出给我们。

如果再加一点额外的努力,还可以保留有关权限甚至文件删除的信息。毕竟,这就是当您进行实际提交时 Git 所做的事情。

有人可能会认为在想要将更改存储以供将来参考时,所有这些步骤都是有用的,但不想为每个小更改污染索引,因此可能在内部测试中使用 发布。在这种情况下,您可以将本地哈希记录为代码的实际版本,而不仅仅是非描述性的 -dirty 标志,以查看您的代码失败的确切位置,当您忘记为每个工作版本打标签或提交时。有人可能认为这是一个坏习惯,应该强制您对每个成功构建进行提交,无论多么小——这很难争辩,但这只是为了方便。


我认为你可以删除-w选项,因为没有必要将永远不会提交的东西放入仓库中。 - jthill
感谢修改。但是,我想保留关于使用diff来比较单个文件(而不是整个树形结构)的注释(感谢您指出)。即,我们首先使用“git diff-tree -r HEAD hash”来查找此树与HEAD(或任何其他提交)之间的差异,然后找到已更改的有兴趣的文件 的哈希值(其他文件将在新树中显示为“0000”),然后我们可以直接使用“git diff hash_old hash_new”来仅显示更改内容。这有点复杂,但可能值得这样做。 - dan
此外,您的新版本缺少 hash-object-w 开关,因此我们无法像上面描述的那样使用 diff。它需要存在以启用此功能。 - dan
Gaak。git hash-object -w - jthill
1
为了避免污染Git索引数据库,我们可以创建临时文件夹:t = $(mktemp); GIT_DIR = $ t git init,然后为git hash-objectgit mktree命令添加前缀GIT_DIR = $ t - James Z.M. Gao
显示剩余3条评论

3

如果你只想确定是否存在未提交的修改,那很容易;只需运行git diff --quiet HEAD并检查返回代码是否非零。

如果你实际上需要一些更改的哈希值,以便两个具有相同初始提交和相同本地修改的用户将得到相同的哈希值,那就比较棘手了。我的第一个想法是将git diff HEAD的输出导入sha1sum,并将其连接到提交哈希值,但是git diff的输出可能因为不同的Git版本和配置选项而有所不同。

或者,你可以使用git add -u . && git write-tree来获取当前工作树的诚实可靠的Git树对象。但这是一种破坏性操作,它会覆盖已经在索引中部分暂存的更改。


你可以将 git diff --quiet && <compile-command> 结合起来,这样如果 git diff 返回非零值,就不会进行编译。然而,如果只有未跟踪的文件,git diff --quiet 仍将返回0。但是,做一次 git status 然后再启动源代码的构建/编译真的有多难呢? - user456814

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接