我需要在发行期间将各种版本的代码推送到git,并在发生问题时回滚到以前的版本。
我们正在使用标签进行发布。
对于回滚,我想检查代码文件夹是否在先前的标记中。
我知道我可以使用git-cat文件,但这对我来说没有帮助,因为代码在部署到我们的过程中之前已经在分支中。
是否可以检查git标记中是否存在文件夹?然后,我想使用mt脚本的返回值。
您没有提出的问题有一个相对直接和简单的答案,那就是:只需运行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到达非标签对象剥离标签。剥离标签最终会导致其余可能的对象类型之一:commit,tree或blob。
因此,从技术上讲,没有标签曾经存储过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
中的快照。
一个树对象包含一个三元组的数组:
这里是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]
请注意,普通文件(例如
对象引用存储在此顶级树中。但是,COPYING
和GIT-VERSION-GEN
)如何作为blobDocumentation
不是任何文件的名称。提取此提交后,某些文件的名称将<< [开始于
Documentation/
。这是树d12f433f975c365f2516022fd6ba597548a12a55
中的一些内容:$ git cat-file -p d12f433f975c365f2516022fd6ba597548a12a55
[snip]
100644 blob aa828dfdc44a856c8bdd8b0826defeb398113bcc MyFirstObjectWalk.txt
040000 tree 467d9eb934bfbb8ff63f5d239b2d4c975ab8e9b9 RelNotes
100644 blob 4515cab5193ddf354a461aafb1b68dcc1ef2932e SubmittingPatches
[snip]
这向我们显示了提取此提交后,您可以使用一些文件,其中一个文件名为与此索引最接近的是它can存储gitlink名称。 Gitlinks具有模式Documentation/MyFirstObjectWalk.txt
,另一个文件名为Documentation/SubmittingPatches
。由于还有一个名为RelNotes
的子树,因此必须存在名称以Documentation/RelNotes/
开头的文件。1
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 cat-file -t v2.23.0:Documentation
tree
比以下提供更多信息:
$ git rev-parse v2.23.0:Documentation
b55461e880f78ae8253c8be287476cbbddd44957
所以这是要走的路。
如果将
2
tree object
称为“文件夹”,则可以声称该提交确实包含一个文件夹,但是Git的实际工作方式并不完全如此。如果子树对象中包含files,则该子树对象只能存在于提交中。有时候确实很烦,但是确实如此。3当git checkout
从包含sub/one
和sub/two
的干净签出的提交移动到具有no文件的提交时,操作系统需要放置该文件在名为sub/
的文件夹中,Git当然会从工作树中删除这两个文件。它们现在在索引和工作树中,但是在目标提交中,它们必须消失。删除两个文件后,Git还将从工作树中删除空的sub/
文件夹。如果sub/
文件夹不是