为什么在描述干净的检出时,`git describe -dirty`会添加`-dirty`后缀?

9
我刚刚发现了--dirty选项,它可以在git describe的输出中添加后缀,用于指示工作树是否有更改。但是,在我的一些存储库中似乎并不起作用。
$ git status
# On branch 8.30
nothing to commit (working directory clean)
$ git describe --dirty
8.30rel-8-g9c1cbdb-dirty

我认为这可能是因为工作目录相对于标记 而言不干净,但实际上情况并非如此:

$ git status
# On branch 1.4
nothing to commit (working directory clean)
$ git describe --tags --dirty --long
1.4rel-0-gfedfe66-dirty

我曾经使用Mercurial时广泛使用hg id,并喜欢它的默认行为是向任何报告脏库的提交哈希添加+后缀,因此一直在寻找git的等效命令,但根据文档,git describe --dirty似乎没有达到我的期望:

   --dirty[=<mark>]
       Describe the working tree. It means describe HEAD and appends
       <mark> (-dirty by default) if the working tree is dirty.

我是否误解了--dirty的作用,或者我没有正确使用它?

如果有任何区别的话,所有的git仓库都是通过buckminster部署的,因此没有涉及到任何子模块,文件系统是一个nfs共享。


更新:我发现了一个解决方法,但我完全不知道这可能会有什么影响。
如果在存储库上运行git diff --quiet HEAD,那么突然间git describe按我所期望的方式工作:
$ git status
# On branch 8.30
nothing to commit (working directory clean)
$ git describe --dirty
8.30rel-8-g9c1cbdb-dirty
$ git diff --quiet HEAD
$ git describe --dirty
8.30rel-8-g9c1cbdb

我还注意到,当git describe 报告存储库为dirty时,gitk也会显示“本地未提交的更改,未检入索引”,然后列出工作目录中的每个文件,但没有与它们的差异,只有---- 文件名 ----行。
进一步更新: 由于这一问题持续存在,我最终编写了一个名为git-describe-dirty的脚本,该脚本首先运行git describe --dirty命令,但如果发现存储库处于脏状态,则在再次尝试并获取第二个结果之前运行git update-index -q --refresh命令。

当迭代数百个存储库时,使用git describe-dirty并仅为最初指示其处于脏状态的存储库运行索引更新,可节省大量时间,而不是每次运行git update-index -q --refresh ; git describe --dirty


你的项目中有子模块吗? - 1615903
注意:使用Git 2.13(2016年第二季度),您不仅需要考虑“-dirty”,还需要考虑“-broken”。请参见下面的我的答案 - VonC
3个回答

12
如果您正在运行git 1.7.6或更早版本,则需要在使用git describe --dirty之前运行git update-index --refresh,因为索引可能过时。您使用git diff --quiet HEAD的解决方法有效,因为“git diff”是一个外壳命令,可能会更新索引本身。
修复git 1.7.7的git提交描述了这个问题:
当运行git describe --dirty时,应该刷新索引。以前,缓存的索引会导致describe认为索引是脏的,而实际上它只是过时了。
请注意,您描述的确切步骤不应该出现此问题,因为git status会更新索引。但我仍然认为您看到了相同的问题,因为您描述的解决方法匹配。以下是我演示问题的方式:
% git describe --tags --dirty
v1.0.0
% touch pom.xml
% git describe --tags --dirty
v1.0.0-dirty
% git status
# On branch dev
nothing to commit (working directory clean)
% git describe --tags --dirty
v1.0.0

在这里,运行"git status"会作为副作用更新索引并修复"git describe"的输出,就像您的解决方法一样。对于git 1.7.6及更早版本的正确管道修复方法是:
% touch pom.xml
% git describe --tags --dirty
v1.0.0-dirty
% git update-index --refresh
% git describe --tags --dirty
v1.0.0

这里有一个测试脚本,演示了修复之前的问题。请注意,describe确实是瓷器,并且已经按照@peritus的建议进行了修复,尽管Twitter讨论似乎表明相反。(请参阅瓷器命令列表) - jbyler
关于过期索引的更多背景信息和为什么在管道级别命令中预期会出现这种情况,请参见此讨论 - jbyler

3
注意,大约一年前有关于 git describe --dirty 的另一个错误修复: https://github.com/git/git/commit/a1e19004e11dcbc0ceebd92c425ceb1770e52d0b

"git --work-tree=$there --git-dir=$here describe --dirty" 无法正确工作,因为它没有注意到用户指定的工作树位置。

在出现此错误的情况下,这里展示的解决方法均未起作用,因此我们不得不升级我们的安装。截至今天(2020年02月20日),似乎还没有适用于 Debian buster 的可用修复方案,但 Debian bullseye 主要的 Git 包目前与 buster 兼容。


是的,您可以在https://dev59.com/BW_Xa4cB1Zd3GeqPwxGQ#55082980上查看更多详细信息。 - VonC

2

Git 2.13(Q2 2017)在--dirty标志上进行了一些改进,增加了一个--broken标志,因为当无法确定工作树中的状态是否与HEAD匹配(例如损坏的存储库或子模块)时,“git describe --dirty”会失败。

请参见commit b0176ce(2017年3月21日),作者是Stefan Beller(stefanbeller
(由Junio C Hamano -- gitster --commit 844768a合并,2017年3月27日)

builtin/describe: 引入 --broken 标志

git-describe 告诉您所在的版本号,或者出现错误,例如在不在存储库中运行它时(可能会在下载 tarball 而非使用 git 获取源代码时发生)。 为了保持这种仅出错而不在存储库中的特性,必须将严重(子模块)错误降级到轻松报告而非完全错误。 为了实现这一点,引入了一个'--broken' 标志,该标志与 '--dirty' 相同,但使用实际的子进程来检查脏数据。 当该子进程意外死亡时,我们将附加 '-broken' 而不是 '-dirty'。
请注意,从 Git 2.41 (Q2 2023) 开始, "git describe --dirty"(man) 将更好地与稀疏索引一起使用。

请查看提交 748b8d6(2023年4月3日)由Raghul Nanth A (NanthR)提交。
(由Junio C Hamano -- gitster --合并于提交 7ac228c,2023年4月21日)

describe:为描述启用稀疏索引

签署者:Raghul Nanth A

git describe(man) 命令在运行时(只有在使用 "--dirty" 标志时)会将索引与工作树进行比较。
这是通过 run_diff_index() 函数实现的。
该函数已经意识到了稀疏索引在导致 8d2c373 ("Merge branch 'ld/sparse-diff-blame'", 2021-12-21, Git v2.35.0-rc0 -- merge listed in batch #4) 系列中的作用。
因此,我们可以将 "describe" 的 requires-full-index 设置为 false。
请参阅 "如何在2.27+中使用git sparse-checkout" 以了解更多关于sparse-index的内容。

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