我正在尝试确定与特定标记关联的提交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
检出第一次提交,然后查看日志,我实际上并不在6a390c
;显示b6dcf8
。
任何人都可以解释为什么可能会断开连接?当我尝试结帐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_tag
和my_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
标签在某个时刻存在,但它似乎不再存在。
答案 0 :(得分:3)
执行“git show my_tag”并看到两个标签,因为my_tag标签是使用my_tag_Build_1标签作为参数创建的,如下面的命令所示:
git tag -m "Tagging Release my_tag" -a my_tag my_tag_Build_1
另一方面,我不能解释为什么my_tag_Build_1没有显示在“git tag”命令中。这真的很奇怪。
答案 1 :(得分:3)
即使Marcelo Ávila de Oliveira's answer正确,我还会再添加一个答案,因为我想绘制图形位。 : - )
通常我喜欢这样绘制提交图,至少对于StackOverflow:
...--A--B--C <-- foobranch
\
D--E <-- barbranch
这里有两个 tip (最右边)提交两个分支C
和E
,每个分支都有一个指向它们的分支名称。也就是说,refs/heads/foobranch
包含提交C
的ID,refs/heads/barbranch
包含提交E
的ID。
轻量级标签的工作方式与分支名称完全相同。如果我们添加标记bartag
以指向提交E
,我们会得到:
...--A--B--C <-- foobranch
\
D--E <-- barbranch, tag: bartag
其中refs/heads/bartag
(.git
中的实际文件,除非它已成为&#34;打包&#34;而现在存储在文件.git/packed-refs
中)也存储了ID提交E
。轻量级标记和分支之间有三个区别:
refs/tags/
而不是refs/heads/
开头。 轻量级代码,只是一个全名拼写为refs/tags/...
的引用。此外部引用存在于某处 - 通常作为单独的文件,如.git/refs/tags/bartag
- 它指向存储库中的Git对象(.git/objects/...
,可能打包到包文件中)。当它指向一个提交时,这是正常情况,这会让我们进入提交DAG:标签定位提交,它可以为我们提供工作树,并且还允许我们通过跟随&来探索早期(祖先)提交#34;父&#34; ID,从提交E
返回D
。
带注释的标签使用几乎相同的图片,除了现在,而不是将直接指向的轻量级标签bartag
,现在Git存储带注释的标签对象进入存储库。此带注释的标记对象具有自己的数据(日期,标记,消息,可选的数字签名以及您喜欢的任何其他内容),并且还存储一个哈希ID。哈希ID是标记的目标(或object
,正如Git所说的那样)。
我不喜欢在这里画这些,所以我只是做点什么:
...--A--B--C <-- foobranch
\
D--E <-- barbranch
^
:
t <-- tag: annotag
在这里,Git在存储库中存储了一个新的带注释的标记对象t
,现在我们将外部引用refs/tags/annotag
指向t
。同时,标记对象t
指向提交E
。
这意味着标记annotag
涉及两个哈希ID:带注释的标记对象的ID,以及提交E
的ID。同样,引用指向带注释的标记对象,对象指向下一个 - 在这种情况下,提交E
。
与轻量级标记一样,带注释的标记对象可以指向除提交之外的其他对象类型。轻量级标记不能指向带注释的标记对象,但这只是因为,当引用指向带注释的对象时,我们不再调用它&#34;轻量级&#34;标签,我们现在称之为&#34;注释&#34;标签。但是,带注释的标记对象可以指向另一个带注释的标记对象。让我们这样做,让zomgtag
指向对象t
:
...--A--B--C <-- foobranch
\
D--E <-- barbranch
^
:
t <-- tag: annotag
^
:
z <-- tag: zomgtag
现在让我们尝试删除标记annotag
。关于Git的一个有趣的事情是删除引用 不实际上删除了底层对象。通常会留下底层对象,直到存储库中的垃圾太多,此时Git会为您运行git gc --auto
。 GC(垃圾收集器)查找未引用的对象并实际删除它们。因此,这个GC是一种死神,或者可能是Grim Collector,它将死对象回收到可用的磁盘空间。
对于分支名称引用也是如此,例如:删除分支名称只是放弃分支提示,而不是实际删除它。此外,如果有一些其他方式来达到该提交,那么即使Grim Collector过来,提交本身也不会消失。如果还有一些联系,GC会将对象留在原位。对于普通(未删除)分支,当您进行rebase(将提交链复制到新链)时,原始提交链提示ID存储在分支的 reflog 中,这将保留整个链可以到达,直到reflog条目到期。 (这意味着您可以默认返回并恢复已重新提交的提交至少30天,因为30天和90天是默认的reflog到期时间。)
但是这些相同的规则适用于带注释的标签对象!因此,如果我们在离开annotag
时删除zomgtag
,则现在是:
...--A--B--C <-- foobranch
\
D--E <-- barbranch
^
:
t
^
:
z <-- tag: zomgtag
标记对象t
不再有名称,但可通过z
到达<{em>},我们通过{{1}到达所以refs/tags/zomgtag
永远存在于存储库中。 (好吧,除非t
也被删除,否则zomgtag
会被取消引用。)
现在t
中有两个 Git对象:从外部引用开始,我们找到带注释的标记对象zomgtag
。从中我们找到带注释的标记对象z
,从t
我们找到提交t
。
Git在the gitrevisions
documentation中描述了一种特殊的语法,用于&#34;剥离&#34;标签:E
。描述说:
后缀为
zomgtag^{}
后跟空括号对意味着该对象可以是一个标记,并递归取消引用该标记,直到找到非标记对象。
如果我们制作更多带注释的标签,我们可以让^
指向一个标签对象,该对象指向指向另一个标签对象的第二个标签对象,最终,在跟随许多标签之后,指向{{ 1}}指向refs/tags/wacky
,指向z
。符号t
表示&#34;找到非标签对象&#34; (在这种情况下,提交,尽管一如既往,端点也可以是树或blob)。
答案 2 :(得分:2)
您的标记可能是一个打包标记,这意味着已将一堆引用放入一个文件中以提高传输效率。来自gitrepository-layout
文档:
packed-refs
records the same information as refs/heads/, refs/tags/, and friends record in
a more efficient way. See git-pack-refs(1). This file is ignored if
$GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/packed-refs" will be used instead.
传统上,分支和标签的提示(统称为refs)在$ GIT_DIR / refs目录下的(子)目录中每个ref存储一个文件。虽然许多分支提示往往会经常更新,但大多数标签和一些分支提示永远不会更新。当存储库有数百或数千个标记时,这种one-file-per-ref格式既浪费存储又会损害性能。
看看.git/packed-refs
,您会看到类似的内容。
6a390ca7bca7b52b2009069138873fdbc7922c1d refs/tags/my_tag
^b6dcf8fa20296d146e9501ab9d25784879adeac8
标签基本上是指向提交的对象。您可以使用-d
解决此问题,以取消引用该标记。你应该看到这样的东西:
git show-ref -d my_tag
6a390ca7bca7b52b2009069138873fdbc7922c1d refs/tags/my_tag
b6dcf8fa20296d146e9501ab9d25784879adeac8 refs/tags/my_tag^{}