【问题标题】:Git: get a hash of the current state of the working tree?Git:获取工作树当前状态的哈希?
【发布时间】:2015-09-19 07:40:35
【问题描述】:

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

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

但是,有时我在对代码进行小的更改后重新编译而不进行提交。然后这个方法不起作用,因为它只考虑提交的更改。

是否有任何便捷的方法可以使用 git 或其他方式以编程方式获取当前提交的哈希以及工作目录的状态?

另外,这种做法有名称吗?

【问题讨论】:

  • 为什么不记得在编译之前提交呢?在开始编译之前,您应该能够以编程方式检查工作副本是否在脚本中被修改/修改。

标签: git version-control


【解决方案1】:

可以在当前工作树中创建和存储大部分更改,包括所有暂存、未暂存和未跟踪的文件,同时尊重 .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

第一个差异列出了所有不同于 HEAD 的跟踪文件。

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

然后我们将这两个命令的输出通过管道传输到一个循环中,tnat 为所有文件构造git mktree 输入。

它的输出通过sed,因为git mktree 不递归地构造树,但是这里的实际路径并不重要,因为我们只需要一个哈希码,没有任何实际内容被存储以供检索。

最后,我们将这个ls-tree格式化的输出传递给mktree,它构造指定的树并将其存储在Git中,将hash输出给我们。

通过一些额外的努力,您还可以保留有关permissions 的信息,甚至可能是文件删除。毕竟,这就是 Git 在您进行实际提交时所做的事情。

人们可能会争辩说,当您确实希望存储更改以供将来参考但又不想因每一个微小的更改而因不必要的提交而污染索引时,所有这些箍都是有用的。因此,它可能对使用 micro-releases 进行内部测试很有用,您可以在其中将本地哈希记录为代码的实际版本,而不仅仅是非描述性的 -dirty 标志,以查看当您忘记为每个工作版本标记或提交代码时,您的代码究竟在哪里失败。有些人可能认为这是一个坏习惯,它应该迫使你为每一个成功的构建做出承诺,无论多么小——这很难反驳,但话又说回来,这一切都是为了方便。

【讨论】:

  • 我认为你可以取消 -w 选项,理论上没有必要将你永远不会提交的东西放入 repo 中。
  • 这真是太聪明了。子目录中的路径对git mktree 无效,但没有理由关心,因为您只是为哈希码做它,在\` makes an acceptable path for git mktree 中进行Subbing,一切正常。对此表示敬意。它确实绕过了子模块和符号链接,如果工作繁琐,处理这些将需要一些相当简单的,但这也可能没问题。我冒昧地在清理后的版本中进行替换,并纠正了一些小错误,而不是为其添加单独的答案
  • 感谢您的编辑。但是,我会保留有关使用 diff 比较单个文件的说明(不是整个树,感谢您指出这一点)。 IE。我们首先使用git diff-tree -r HEAD *hash* 来发现这棵树和 HEAD(或任何其他提交,就此而言)之间的差异,然后找到更改的感兴趣的 file 的哈希值(其他将显示 '0000' 在新树),那么我们可以直接git diff *hash_old* *hash_new* 显示仅更改。有点参与,但可能值得。
  • 另外,你的新版本缺少-w 开关hash-object,所以我们不能像上面描述的那样使用差异。它需要在那里才能启用此功能。
  • 为了避免污染git索引db,我们可以创建一个temp:t=$(mktemp); GIT_DIR=$t git init,然后为git hash-objectgit mktree命令前缀GIT_DIR=$t
【解决方案2】:

如果您只想确定是否存在任何未提交的修改,那很容易;只需运行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 有多难?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-06
  • 2014-06-04
  • 2012-02-11
  • 2013-05-01
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多