4

我有一个问题,两个类似的进程在同一存储库的不同克隆中并行运行(通常在不同的计算机上)。每次进程运行时,它都会从远程获取最新的标签,然后根据它看到的标签推断出一个唯一的数字。

例如,如果遥控器上存在这些标签:1.0 1.1 1.2 1.3,那么进程将选择 1.4 作为下一个数字。

在该过程开始之前,它会创建一个新标签并将其推送回远程:

$ git tag 1.4 HEAD
$ git push origin tag 1.4

这个想法是,这是一种原子选择数字的方法。另一个进程,如果它同时查看,可能也决定使用 1.4,但是当它推送它的标签时,它应该发现 1.4 已经存在,并选择 1.5 代替(然后再试一次)。

我希望我可以将 git 标签推送视为原子的。

不幸的是,由于某些奇怪的原因,git 允许远程标签在某些情况下移动!

例如,假设标签 1.4 已放在 origin/master 上并推送。另一个进程想要将标签 1.4 放在例如 origin/master^ 上,这将涉及向后移动标签。Git 会以“非快进”错误拒绝此操作:

过程一:

$ git tag 1.4 origin/master
$ git push origin tag 1.4
Total 0 (delta 0), reused 0 (delta 0)
To /repo1
 * [new tag]         1.4 -> 1.4

过程乙:

$ git tag 1.4 origin/master^
$ git push origin tag 1.4
To /repo1
 ! [rejected]        1.4 -> 1.4 (non-fast forward)
error: failed to push some refs to '/repo1'

好的,没关系,进程B可以用这个来试试1.5。

但是考虑一下这种情况:

过程一:

$ git tag 1.4 origin/master
$ git push origin tag 1.4
Total 0 (delta 0), reused 0 (delta 0)
To /repo1
 * [new tag]         1.4 -> 1.4

过程乙:

$ git tag 1.4 origin/master
$ git push origin tag 1.4
Everything up-to-date

哦。真可惜——git 没有表明这个标签已经存在于遥控器上。实际上,使用 -v 确实如此:

$ git push origin tag 1.4 -v
Pushing to /repo1
To /repo1
 = [up to date]      1.4 -> 1.4
Everything up-to-date

好的,所以我可以进行某种标准错误重定向,搜索“=”,这将允许进程 B 确定 1.4 已经在使用中。

但这有点傻。情况变得更糟:

过程一:

$ git push origin tag 1.4
Total 0 (delta 0), reused 0 (delta 0)
To /repo1
 * [new tag]         1.4 -> 1.4

过程乙:

$ git push origin tag 1.4
Total 0 (delta 0), reused 0 (delta 0)
To /repo1
   fd0e09e..c6cdac9  1.4 -> 1.4

阿格!什么?Git刚刚移动了远程标签而没有警告!

所以在我看来,git 中的远程标签从根本上被破坏了——它们不应该在没有明确请求的情况下“移动”。更重要的是,他们应该默认拒绝移动。

此外, git-tag 命令应该提供一种自动测试和设置标签的方法。

但显然不是。首先运行 git fetch 并没有帮助,因为仍然存在冲突窗口,即使存在冲突,在三种情况之一中,标签只会移动!

这里发生了什么?

还有另一种测试和设置标签的方法吗?

如果没有,人们如何在自动构建环境中分配和保留构建号?您如何可靠地检测两个进程何时无意中获取了相同的内部版本号?

使用 git 1.6.1.2。

4

1 回答 1

8

我认为如果您使用真正的标签对象而不是轻量级标签,那么您的标签策略将是最好的选择,轻量级标签更多地设计为本地标签。

-a您可以通过指定(或-m/ -F-s-u选项( )之一来创建标记对象git help tag

尝试您的示例,但添加-m "1.4 tag"git tag. 标记对象不能引导其他标记对象的后代,因此您想要在上面失败的每个推送案例都应该失败。

于 2009-07-23T07:33:13.153 回答