git 验证是否在主分支中完成了标记

3mpgtkmj  于 2022-11-20  发布在  Git
关注(0)|答案(4)|浏览(133)

在我正在做的这个项目中,我们基于标签进行部署。虽然标签必须针对master分支进行(在您合并发布之后),但有时候错误地有人可以针对dev或release分支进行标签,这是不正确的。这会导致几个问题。
在我们的部署脚本中,有一个步骤,我们从git克隆一个特定的标签,使用类似于这个问题中描述的过程:Download a specific tag with Git

$ git clone
$ git checkout tags/<tag_name>

我如何修改这个脚本来检查这个标记是否真的是针对master分支完成的?如果分支不是master分支,我想停止部署并抛出一个错误。

  • 谢谢-谢谢
gywdnpxw

gywdnpxw1#

git分支-a --包含|grep主机|切割-d/ -f3
示例:git分支-a --包含v.1.2.3| grep主机|切割-d/ -f3

pgky5nke

pgky5nke2#

简而言之,你不能。至少事后不能。
你可以做的就是创建一个 annotated tag。这会在tag上放置一个消息。然后这个消息可以包含当前 checkout 分支的分支名称。然后你可以检查这个消息是否包含master
另一个解决方案是使用pre-push commit钩子来检查要推送的任何新标签是否可以从master分支到达。
这两种解决方案都需要在客户端进行设置,因此可能会被愚蠢或恶意的用户绕过或禁用。
如果你可以控制你的Git仓库管理器,你可以考虑为相同的可达性标准进行预接收钩子测试。
我的建议是找出正确的方法来自动化您的释放标记过程。
祝你好运!

flmtquvp

flmtquvp3#

正如一些人所指出的,你的问题在重新表述之前无法得到真正的回答。这是因为Git标签或分支名称只是标识 * 一个特定的提交。* 分支名称的预期效果是标识分支的 tip 提交,它会随时间而变化,因此它标识的特定提交也会随时间而变化。标签名称的预期效果是永远标识一个特定的提交,因此,如果某人标记了master,在某些时刻,解析名称master会产生提交哈希 H,解析标签名称 * 也 * 会产生提交哈希 H:

if test $(git rev-parse master) = $(git rev-parse $tag^{commit}); then
    echo "master and $tag both identify the same commit"
else
    echo "master and $tag identify two different commits"
fi

这个测试一直有效,直到有人把分支名称master设置为advance,之后它就不再有用了。如果我们用我在StackOverflow上绘制Git提交图的方式来绘制,我们可以看到:

tag
           |
           v
...--o--o--H   <-- master
          /
 ...--o--o   <-- develop

目前,tagmaster都标识提交H,这是一个合并提交。但是,一旦有人在master上创建了一个 * 新 * 提交,图表就会变成:

tag
           |
           v
...--o--o--H--I   <-- master
          /
 ...--o--o   <-- develop

现在master标识新提交I,因此执行rev-parse tag^{commit}将找到H,而执行rev-parse master将找到I,它们将不相等,测试将失败。
(我在这里把I作为一个普通的提交,但它也可能是一个带有第二个父提交的合并提交。如果是这样,想象第二个向后指向的线/箭头从I出现,指向其他更早的提交。
Philippe's answer有两种形式,并且回答了一个稍微不同的问题。由于分支名称 * 会 * 随着时间的推移而移动,我们可以使用git branch --contains来查找 * 所有 * 使标记提交可达的分支名称,并查看其中是否有一个是master。对于上面的情况,这将给予正确/是的答案。不幸的是,它还将告诉您标签error包含在master中-这是真的!-对于 * 这个 * 图:

tag
           |
           v
...--o--o--H   <-- master
          /
 ...--o--G   <-- develop
         ^
         |
       error

这是因为标签error标识提交G,并且提交G是从 * 提交H * 可达的(通过跟随H的第二父提交)。实际上,沿着底部行指向包含在develop分支内的任何提交的任何标签标识包含在master分支内的提交,因为 * 当前在develop上的每个提交也在master上 *。
(顺便说一句,使用git rev-parse your-tag和使用git rev-list -n 1 your-annotated-tag之间的区别可以通过使用git rev-parse $tag^{commit}来解决。这里的问题是,带注解的标记有一个实际的存储库对象,类型为“annotated tag”,名称指向该对象;单独使用git rev-parse your-annotated-tag会找到 tag 对象,而不是它的提交。^{commit}后缀语法在the gitrevisions documentation中有描述。)
有一种方法可以判断任何给定标记所指向的提交是否在master的历史记录中,并且只发生在第一个父链上。git branch --containsgit merge-base --is-ancestor是用于查找可达性的常用构建块,但是它们都跟随 * 所有 * 父节点。我们需要使用git rev-list --first-parent来枚举所有从名字master可以到达的提交,然后我们简单地检查标记的版本号是否在列表中。这里'It“如果我们把自己的工作搞得很清楚,那就不好了:

tagged_commit=$(git rev-parse $tag^{commit}) ||
    fatal "tag $tag does not exist or does not point to a commit object"
found=false
for hash in $(git rev-list --first-parent master); do
    test $hash == $tagged_commit && found=true
done

为了更快地完成这一过程,最好将git rev-list的输出通过一个grep来搜索$tagged_commit(由于我们只关心状态,因此丢弃grep的输出):

if git rev-list --first-parent master | grep $tagged_commit >/dev/null; then
    echo "$tag points to a commit reachable via first-parent from master"
else
    echo "$tag does not point to a commit reachable via first-parent from master"
fi

(这里的一个缺陷是git rev-list将一直运行到每个可到达的提交;在大型存储库中,这可能需要 * 秒 *。)

e4eetjau

e4eetjau4#

如果是轻量型标签:

git branch --contains $(git rev-parse your-tag) | grep '^* master$'

对于带注解的标记:

git branch --contains $(git rev-list -n 1 your-annotated-tag) | grep '^* master$'

如果标记指向的提交位于master中,则结果不应为空。(您甚至可以测试grep的退出代码,如果位于master中,则返回0,否则返回1。)

相关问题