首页 > 解决方案 > `git ls-remote --tags` 和 `git tag` 命令之间的标签计数差异。为什么?

问题描述

我刚刚注意到git ls-remote --tagsgit pull && git ta返回不同的结果:

git ls-remote --tags | wc -l: 75417

git tag | wc -l: 75264

这种差异有什么解释吗?假设我的本地存储库仅包含一个远程(来源),并且远程存储库没有使用新标签进行更新,我希望这两个命令都返回相同的标签,但它们不会。为什么?

标签: git

解决方案


您的案例是“信息过多”之一git ls-remote

在您的情况下,您确实具有相同的标签,正如您在评论中发现并提到的那样。 但这git ls-remote只是要做的第一步git fetch:调用另一个 Git 存储库并让它列出其分支和标签名称,以及它们相应的哈希 ID。这就是您--tags在此处使用的原因,将列表缩减为仅标记名称。

出于git fetch的目的,当远程列出其标记名称时,它不仅列出标记本身的内部 Git 哈希 ID,1还列出标记对象的内部 Git 哈希 ID,通常是一些提交对象。这允许git fetch以后知道它是否已经获得了提交对象,因此应该创建相应的标签(参见下面的部分)。因此,对于这些标签中的每一种(参见脚注 1),您将获得两个输出行。带有^{}后缀的行代表已解析的标签:请参阅gitrevisions 文档


1 Git 的标签在内部有两种风格:轻量级标签带注释的标签。Git引用(任何以开头的内部 Git 名称refs/)包含 Git 对象的哈希 ID。2标记名称是以 . 开头的 引用refs/tags/。根据定义,带注释的标签是一个标签名称,其哈希 ID 是 Git 带注释的标签对象的 ID 。Git 对象本身有四种类型:committreeblobannotated tag,因此如果标签名命名的不是带注释的标签,则该标签根据定义是轻量级标签。

带注释的标记对象本身包含另一个 Git 哈希 ID。该哈希 ID 必须是某个带注释的标记、提交、树或 blob 的 ID。所以 Git 可以取消引用这个 ID 来查找底层对象。如果那是另一个带注释的标签,Git 会根据需要继续取消引用,以找到一些非标签对象。该链最终需要通过到达一个非标签对象而结束,并且该非标签对象是标签的目标。这就是tag-name^{}发现的。

2这忽略了 Git 所谓的符号引用,它包含另一个引用的名称而不是哈希 ID。此外,Git 的伪引用(如CHERRY_PICK_HEADHEADMERGE_HEADORIG_HEAD等)不以refs/;开头。Git 对于伪引用是引用还是其他东西有点不一致。


Git 存储库不需要具有相同的标签

不要求两个不同 Git 存储库中的标记集匹配。

的默认操作(它本身实际上是 plus 的包装器git fetch,而直到最近实际上是一个包装器并且仍然有效)是复制指向在操作期间获取的提交的任何标记。因此,如果源存储库具有指向默认情况下获取的提交的标签,例如,不在任何分支上,则默认情况下不会获取这些标签。那会产生你展示的那种结果。git clonegit initgit fetchgit pullgit fetchgit fetch

(请注意,如果您在本地创建标签并且不将它们推送到其他 Git,则会产生相反的效果。)

要更详细地查看事物,请将获取的标签保存在文件中,并将实际标签转储到文件中,然后比较两个文件以找出哪些标签不同。(或者,在 bash 中,使用Thomas 的建议。)


推荐阅读