在我正在工作的这个项目中,我们基于标签进行部署。虽然标签是针对主分支完成的(在你将其释放到那里之后),但有时候有人可能会对dev或release分支进行标记,这是不正确的。这会导致一些问题。
在我们的部署脚本中,我们使用类似于此问题中描述的流程从git克隆特定标记:Download a specific tag with Git
$ git clone
$ git checkout tags/<tag_name>
如何修改此脚本以检查此标记是否实际针对主分支执行?如果分支不是主服务器,我想停止部署并抛出错误。
感谢。
答案 0 :(得分:4)
git branch -a --contains | grep 大师 | cut -d/ -f3
示例: git branch -a --contains v.1.2.3 | grep 大师 | cut -d/ -f3
答案 1 :(得分:2)
对于轻量级标签:
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)
答案 2 :(得分:1)
简短的回答是你不能。事实上至少没有。
您可以做的是创建带注释的标记。这会在标签上显示一条消息。
然后,此消息可以包含当前检出的分支的分支名称。然后,您可以检查此邮件是否包含master
。
另一个解决方案是使用pre-push
提交钩子来检查要推送的任何新标签是否可以从master
分支到达。
这两种解决方案都需要在客户端进行设置,因此可以被愚蠢或恶意用户回避或禁用。
如果您可以控制您的Git存储库管理器,您可以考虑针对相同的可访问性标准进行预接收挂钩测试。
我的建议是找出自动化发布标记程序的正确方法。
祝你好运!答案 3 :(得分:1)
正如几位人士指出的那样,在重新制定之前,你的问题无法得到真正的回答。这是因为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
提前,之后它不再有用。如果我们通常喜欢在StackOverflow上绘制Git提交图,我们可以将其视为:
tag
|
v
...--o--o--H <-- master
/
...--o--o <-- develop
目前,名称tag
和master
都标识提交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
作为普通提交,但它可能是与第二个父提交的合并提交。如果是这样,想象一下从git branch --contains
出现的第二个向后指向的线/箭头,指向其他一些早先的提交。)
Philippe's answer有两种形式,可以回答一个稍微不同的问题。由于分支名称 do 随着时间的推移而移动,我们可以使用master
来查找所有分支名称,使标记的提交可以访问,并查看其中一个是否{ {1}}。这将给出上述案例的真实/是答案。不幸的是,它还会告诉您标记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}
。这里的问题是带注释的标签有一个实际的存储库对象,类型为“已注释”标记“,标记”,单独使用git rev-parse your-annotated-tag
查找标记对象而不是其提交。the gitrevisions documentation中描述^{commit}
后缀语法。)
是一种判断任何给定标记所指向的提交是否仅在第一父链上发生的master
历史记录中的方法。它不是最漂亮的:git branch --contains
和git merge-base --is-ancestor
是查找可达性的常用构建块,但都遵循所有父项。要仅关注第一个父项,我们需要使用git rev-list --first-parent
枚举所有只能跟踪第一个父项时可从名称master
访问的提交。然后我们只需检查标记的修订是否在该列表中。这是一个很糟糕的方法,可以明确我们正在做的事情:
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
的{{1}}来管道grep
输出(由于我们只关心状态而丢弃了grep的输出) :
$tagged_commit
例如。 (这里的一个缺陷是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
将在每个可达的提交中一直运行;在大型存储库中,这可能需要秒。)