如何检查git标签中是否存在文件夹

问题描述 投票:0回答:1

我需要在发行期间将各种版本的代码推送到git,并在发生问题时回滚到以前的版本。

我们正在使用标签进行发布。

对于回滚,我想检查代码文件夹是否在先前的标记中。

我知道我可以使用git-cat文件,但这对我来说没有帮助,因为代码在部署到我们的过程中之前已经在分支中。

是否可以检查git标记中是否存在文件夹?然后,我想使用mt脚本的返回值。

git tags check
1个回答
0
投票

没有提出的问题有一个相对直接和简单的答案,那就是:只需运行git cat-file -t commit-specifier:path。如果它说存在并且是tree对象,则您指定的提交包含将放入具有该名称的文件夹中的文件。如果它说这是其他某种对象,则您指定的提交不包含此类文件:而是具有此对象。如果这完全失败,则您指定的提交不包含任何具有该名称的对象。因此:

objid="${tagname}:${path}"
objtype=$(git cat-file -t $objid 2>/dev/null) || objtype=none
case $objtype in
none) echo no such folder would be created;;
blob) echo the specified path holds a file rather than a folder;;
tree) echo a folder would be created and contain some files;;
commit) echo the specified path refers to a submodule;;
*) echo something went terribly wrong;;
esac

您可以将各种echo转换为所需的退出状态。这可能是您想要的答案。

回答您的问题,而不是我想您要问的问题

不过,您实际提出的问题是:

是否可以检查git标记中是否存在文件夹?

A tag只是一个名称-通常沿着v2.1或类似的名称-引用某些Git对象。该Git对象通常是带注释的标签对象commit。如果标记名称直接涉及提交,则Git将此称为lightweight tag。如果标签名称引用带注释的标签对象,则Git将此称为带注释的标签。带注释的标签对象然后引用另一个对象。

[在某些情况下,带注释的标签对象的目标对象是另一个带注释的标签。如果是这样,Git可以读取这个second标记对象,它引用了另一个对象。该对象可以是另一个带注释的标签对象:如果是这样,Git会继续阅读和跟踪,直到最终某个带注释的标签对象引用了带注释的标签对象之外的其他对象。换句话说,尽管带注释的标签对象可以通过指向另一个对象来“保持飞行”,但最终所有这些链都照原样“掉落”了。 Git调用此过程,跟随标签对象,直到Git到达非标签对象剥离标签。剥离标签最终会导致其余可能的对象类型之一:committreeblob

因此,从技术上讲,没有标签曾经存储过any文件or文件夹。它只是命名为commit。而且,不幸的是,也没有commit也存储文件夹。幸运的是,这并不重要!

为什么我认为您要问其他问题

Git不存储文件夹的技术原因是它从其index进行了新的提交,而索引无法存储文件夹名称。1它确实采用了索引的files'] >名称,该名称可能很长并且可以包含正斜杠(例如dir/sub/file.ext),并将其分解为component parts。因此,当index拥有一个名为dir/sub/file.ext的文件时,Git将创建一个名为dir的树对象,该树对象引用一个名为sub的树对象,引用一个名为file.ext的Blob对象。稍后我们将看到其工作原理。

回到提交,提交对象保存一个提交。提交代表源的完整快照。在内部,它是通过指向(持有)tree

对象的哈希值来实现的。例如,以下是Git在Git存储库中的实际提交:
$ git rev-parse HEAD
51ebf55b9309824346a6589c9f3b130c6f371b8f
$ git cat-file -p HEAD | sed 's/@/ /'
tree 7db7271b4def298424e57b0a04129f6a929955d0
parent f97741f6e9c46a75b4322760d77322e53c4322d7
author Junio C Hamano <gitster pobox.com> 1581974501 -0800
committer Junio C Hamano <gitster pobox.com> 1581974539 -0800

The sixth batch for 2.26

Signed-off-by: Junio C Hamano <gitster pobox.com>

注意第一行,tree 7db7271b4def298424e57b0a04129f6a929955d0。这是保存在提交51ebf55b9309824346a6589c9f3b130c6f371b8f中的快照。

一个树对象包含一个三元组的数组:。组件名称是路径名称的一部分。该模式是一小组允许的八进制数字之一,代表子树,提交对象(gitlinks)或blob对象(文件和符号链接内容)。如果模式是树或blob对象的模式,则条目必须

中的哈希ID分别是持有树或blob对象的Git对象的模式。

这里是tree对象7db7271b4def298424e57b0a04129f6a929955d0中内容的一部分:

$ git cat-file -p 7db7271b4def298424e57b0a04129f6a929955d0
[snip]
100644 blob 536e55524db72bd2acf175208aef4f3dfc148d42    COPYING
040000 tree d12f433f975c365f2516022fd6ba597548a12a55    Documentation
100755 blob 616d5a6404e4f1a6550b2aca89488889dbe6d34f    GIT-VERSION-GEN
100644 blob 22c364f34f573c615d968a85374ba2c429b7fabd    INSTALL
100644 blob d38b1b92bdb2893eb4505667375563f2d6d4086b    LGPL-2.1
[snip]

请注意,普通文件(例如COPYINGGIT-VERSION-GEN)如何作为blob

对象引用存储在此顶级树中。但是,Documentation不是任何文件的名称。提取此提交后,某些文件的名称将<< [开始于
Documentation/。这是树d12f433f975c365f2516022fd6ba597548a12a55中的一些内容:$ git cat-file -p d12f433f975c365f2516022fd6ba597548a12a55 [snip] 100644 blob aa828dfdc44a856c8bdd8b0826defeb398113bcc MyFirstObjectWalk.txt 040000 tree 467d9eb934bfbb8ff63f5d239b2d4c975ab8e9b9 RelNotes 100644 blob 4515cab5193ddf354a461aafb1b68dcc1ef2932e SubmittingPatches [snip]
这向我们显示了提取此提交后,您可以使用一些文件,其中一个文件名为Documentation/MyFirstObjectWalk.txt,另一个文件名为Documentation/SubmittingPatches。由于还有一个名为RelNotes的子树,因此必须存在名称以Documentation/RelNotes/开头的文件。


1

与此索引最接近的是它can存储gitlink名称。 Gitlinks具有模式160000,这是通过将符号链接模式120000与树模式040000或运算在一起而获得的模式。真遗憾,您无法获得模式040000索引条目,因为would让Git存储空文件夹。
这都意味着什么

如果找到

提交对象哈希ID

,例如,如果存在名为git rev-parse v2.1的标签,则按v2.1,我们可以检查提交对象。它将有一个tree条目。然后我们可以检查该

tree

对象。如果它具有一棵子树,就像上面的一棵有Documentation,那么我们可以假定必须在提交中包含名称为开始于 Documentation/的文件。为了提取这样的提交,Git必须创建名为Documentation的文件夹。提交

不包含该文件夹

2但是提取提交产生]在您的工作树中这样的文件夹。这可能就是您所关心的:例如,extracting提交(使用git checkout),或移至该提交(使用git reset --hard)将创建或删除3这样的提交工作树中的文件夹。通过在每个给定的提交中一次测试每个级别来测试此树对象是否存在,这很痛苦。但是git rev-parse命令可以将

any

有效名称转换为Git对象哈希ID,这使此操作变得容易。因此,虽然您可以运行git rev-parse hash来查看[hash是否是有效的Git对象ID,但是您也可以运行git rev-parse hash:path来查看hash是否可以转换为提交对象,然后从中解析出路径名。该路径名将自动引用某些Git对象。 git rev-parse将产生其哈希ID。尽管我们真的不想要哈希ID。这只是告诉我们某个对象存在,而没有告诉我们该对象具有什么

type

。要找到对象的type,我们需要git cat-file -t。这将获取任何对象的名称或ID并告诉我们类型-如果ID无效,则会产生错误:$ git cat-file -t d12f433f975c365f2516022fd6ba597548a12a55 tree $ git cat-file -t 616d5a6404e4f1a6550b2aca89488889dbe6d34f blob $ git cat-file -t a123456 fatal: Not a valid object name a123456 如果提供带注释的标记对象的标记名称,则会得到:
$ git cat-file -t v2.23.0
tag

将Git标记为

peel标签,使用^{},我们找到了目标对象:

$ git cat-file -t v2.23.0^{} commit

并告诉Git在此提交中查找路径名,我们得到:
$ git cat-file -t v2.23.0:Documentation
tree

比以下提供更多信息:

$ git rev-parse v2.23.0:Documentation
b55461e880f78ae8253c8be287476cbbddd44957

所以这是要走的路。


2
如果将

tree object

称为“文件夹”,则可以声称该提交确实包含一个文件夹,但是Git的实际工作方式并不完全如此。如果子树对象中包含files,则该子树对象只能存在于提交中。有时候确实很烦,但是确实如此。3git checkout从包含sub/onesub/two的干净签出的提交移动到具有

no文件的提交时,操作系统需要放置该文件在名为sub/的文件夹中,Git当然会从工作树中删除这两个文件。它们现在在索引和工作树中,但是在目标提交中,它们必须消失。删除两个文件后,Git还将从工作树中删除空的sub/文件夹。如果sub/文件夹不是

为空,由于存在未跟踪的文件,Git将不是将其删除。现在就可以完成所有工作:Git 创建文件夹要求操作系统存在,以便文件进入其中。在清空容器时,请Git removes将它们清空,但如果不清空它们,则不可以。否则,Git根本不会碰它们。
© www.soinside.com 2019 - 2024. All rights reserved.