gpt4 book ai didi

git - 为什么同一标签有两个不同的git commit?

转载 作者:行者123 更新时间:2023-12-02 06:30:20 54 4
gpt4 key购买 nike

我正在尝试确定与特定标签关联的提交SHA。当我执行show-ref时,我得到以下输出

$ git show-ref my_tag
6a390ca7bca7b52b2009069138873fdbc7922c1d refs/tags/my_tag

当我执行 rev-list时,我得到此输出
$ git rev-list -n 1 my_tag
b6dcf8fa20296d146e9501ab9d25784879adeac8

提交SHA的有所不同,但是我不明白为什么。看来 b6dcf8生成的 rev-list是正确的。如果我尝试使用 git checkout 6a390c checkout 第一次提交,然后查看日志,则实际上我不在 6a390c上;显示 b6dcf8

谁能解释为什么可能会断开连接?为什么在尝试 checkout b6dcf8时重定向到 6a390ca

更新

我还注意到,当我执行 git show my_tag时,我得到的输出看起来像这样
tag my_tag
Tagger: Me <me@me.com>
Date: Mon Apr 4 14:43:46 2016 -0400

Tagging Release my_tag

tag my_tag_Build_1
Tagger: Me <me@me.com>
Date: Thu Mar 31 10:46:18 2016 -0400

Tagging my_tag_Build_1

commit b6dcf8fa20296d146e9501ab9d25784879adeac8
Author: Me <me@me.com>
Date: Wed Mar 30 18:12:10 2016 -0400

Remove secret_key_base values from secrets.yml

它正在拾取两个标签 my_tagmy_tag_Build_1。但是,如果我运行 git tag,标签列表仅包含
my_tag

如果我运行 git show my_tag_Build_1,我得到
fatal: ambiguous argument 'my_tag_Build_1': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:

好像git很困惑。也许 my_tag_Build_1标记已存在,但似乎不再存在。

最佳答案

即使Marcelo Ávila de Oliveira's answer是正确的,我也会添加一个答案,因为我想绘制图形位。 :-)

通常,我喜欢这样绘制提交图,至少对于StackOverflow:

...--A--B--C     <-- foobranch
\
D--E <-- barbranch

这里,两个技巧(最右边)在两个分支 CE上提交,每个分支都有一个指向它们的分支名称。也就是说, refs/heads/foobranch包含提交 C的ID,而 refs/heads/barbranch包含提交 E的ID。

轻量级标签

轻量级标签的工作方式与分支名称完全相同。如果我们添加标签 bartag指向commit E,则会得到:
...--A--B--C     <-- foobranch
\
D--E <-- barbranch, tag: bartag

其中 refs/heads/bartag(实际为 .git的文件,除非已被“打包”,并且现在存储在 .git/packed-refs文件中)也存储了commit E的ID。轻量级标签和分支之间存在三个区别:
  • 轻量标记的全名以refs/tags/而不是refs/heads/开头。
  • 轻量级标签永远不能更改为指向另一个提交(这仅由Git半强制执行,在1.8之前的版本中效果不佳),但分支名称通常会更改它们指向的提交,vs标签,而不是')。
  • Git强制执行一个规则,即分支名称只能指向提交对象。通常,标记名也仅指向提交对象,但是可以使它指向树或Blob。还有另一种对象类型-带注释的标签对象-但这使标签有所不同!坚持这个想法,让我们结束这一部分。

  • 因此,轻量级标记只是其全名拼写为 refs/tags/...的引用。这个外部引用存在于某个地方(通常是像 .git/refs/tags/bartag这样的单独文件),并且指向存储库中的Git对象( .git/objects/...,可能打包成一个打包文件)。当它指向提交时,这是正常情况,这会将我们带入提交DAG:该标签定位该提交,这可以使我们获得工作树,还可以通过遵循“父” ID,从提交 E返回到 D

    带注释的标签

    带注释的标签使用几乎相同的图片,除了现在,而不是轻量级标签 bartag直接指向提交,现在Git将带注释的标签对象存储到存储库中。这个带注释的标记对象具有自己的数据(日期,标记,消息,可选的数字签名以及您喜欢的其他任何数据),并且还存储一个哈希ID。哈希ID是标记的目标(或Git拼写的 object)。

    我没有在这里绘制这些样式的首选样式,因此我将做一些补充:
    ...--A--B--C     <-- foobranch
    \
    D--E <-- barbranch
    ^
    :
    t <-- tag: annotag

    在这里,Git在存储库中存储了一个新的带注释的标记对象 t,现在我们有了指向 refs/tags/annotag的外部参考 t。同时,标记对象 t指向提交 E

    这意味着标签 annotag涉及两个哈希ID:带注释的标签对象的ID和commit E的ID。同样,引用指向带注释的标记对象,而该对象指向下一个对象,在这种情况下,将提交 E

    但是,与轻量级标签一样,带注释的标签对象可以指向除提交之外的其他对象类型。轻量级标签不能指向带注释的标签对象,但这仅是因为当引用指向带注释的对象时,我们不再将其称为“轻量级”标签,而现在将其称为“带注释的”标签。但是,带注释的标签对象可以指向另一个带注释的标签对象。让我们这样做,使 zomgtag指向对象 t:
    ...--A--B--C     <-- foobranch
    \
    D--E <-- barbranch
    ^
    :
    t <-- tag: annotag
    ^
    :
    z <-- tag: zomgtag

    如果您删除其中之一...

    现在,让我们尝试删除标记 annotag。关于Git的一件有趣的事情是,删除引用 并不会实际上删除基础对象。通常会保留底层对象,直到有太多垃圾使存储库混乱为止,这时Git会为您运行 git gc --auto。 GC(垃圾收集器)找到未引用的对象并实际上将其删除。因此,此GC是一种Grim Reaper或Grim Collector,它将死掉的对象回收到可用的磁盘空间中。

    例如,这对于分支名称引用是正确的:删除分支名称只是放弃分支提示提交,而不是实际删除它。而且,如果还有其他方式可以到达该提交,即使Grim Collector过去了,提交本身也不会消失。如果仍有联系,GC会将对象保留在原位。对于普通(未删除)分支,当您进行基础更改(将提交链复制到新链)时,原始提交链提示ID将存储在分支的reflog中,这将使整个链都可访问,直到reflog条目到期。 (这意味着默认情况下,您可以至少恢复30天以恢复重新提交的提交,因为30天和90天是默认reflog到期时间。)

    但是这些规则也适用于带注释的标记对象!因此,如果我们在保留 annotag的同时删除 zomgtag,则图片现在为:
    ...--A--B--C     <-- foobranch
    \
    D--E <-- barbranch
    ^
    :
    t
    ^
    :
    z <-- tag: zomgtag

    标记对象 t不再有名称,但是可以通过 z到达,我们可以通过 refs/tags/zomgtag到达,因此 t永远存在于存储库中。 (好吧,除非也删除了 zomgtag,否则 t变为未引用。)

    现在 zomgtag中涉及两个Git对象:从外部引用开始,我们找到带注释的标签对象 z。从中我们找到带注释的标记对象 t,从 t中找到commit E

    Git在 the gitrevisions documentation中描述了一种特殊语法,用于“剥离”标签: zomgtag^{}。描述说:

    A suffix ^ followed by an empty brace pair means the object could be a tag, and dereference the tag recursively until a non-tag object is found.



    如果我们制作更多带注释的标签,我们可以让 refs/tags/wacky指向一个标签对象,该标签对象指向另一个标签对象,该标签对象又指向另一个标签对象,最终,在跟随许多标签之后,该标签指向 z,该标签指向 t,该标签指向 E 。标记 wacky^{}的意思是“查找非标记对象”(在这种情况下,是一个提交,尽管像往常一样,端点也可以是树或blob)。

    关于git - 为什么同一标签有两个不同的git commit?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39754373/

    54 4 0