为什么git允许远程标签移动,或者为什么你不能使用git-tag进行原子测试和设置

dav*_*idA 4 tags git build-process atomic

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

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

在进程开始之前,它会创建一个新标记并将其推回到远程:

$ git tag 1.4 HEAD
$ git push origin tag 1.4
Run Code Online (Sandbox Code Playgroud)

这个想法是,这是一种原子选择数字的方法.其他进程,如果它在看的同时,也可能会决定使用1.4,但是当涉及到推的标签,就应该发现,1.4已经存在,并选择1.5,而不是(再试).

我希望我可以将git tag推送为原子.

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

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

流程A:

$ 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
Run Code Online (Sandbox Code Playgroud)

流程B:

$ 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'
Run Code Online (Sandbox Code Playgroud)

好的,没关系,进程B可以使用它来尝试1.5.

但请考虑这种情况:

流程A:

$ 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
Run Code Online (Sandbox Code Playgroud)

流程B:

$ git tag 1.4 origin/master
$ git push origin tag 1.4
Everything up-to-date
Run Code Online (Sandbox Code Playgroud)

哦.这是一种耻辱 - 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
Run Code Online (Sandbox Code Playgroud)

好的,所以我可以进行某种stderr重定向,搜索"=",这将允许进程B确定1.4已经在使用中.

但那有点傻.它变得更糟:

流程A:

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

流程B:

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

ARGG!什么?Git刚刚在没有警告的情况下移动了远程标签!

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

此外,git-tag命令应该提供一种原子测试和设置标记的方法.

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

这里发生了什么?

有没有其他方法来测试和设置标签?

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

使用git 1.6.1.2.

CB *_*ley 8

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

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

尝试你的例子,但添加-m "1.4 tag"到每个调用git tag.标记对象不能指向其他标记对象的后代,因此您希望在上面失败的每个推送案例都会失败.

  • 我做了一些挖掘 - 如果第二个进程认为它正在创建一个新标记(即在推送标记之前没有运行git-fetch --tags),它将拒绝第二个进程的标记更新.但是,如果它知道遥控器上存在标签(在提取后按下),那么它似乎允许更新.在我的系统中,我通过确保创建这些独特的标签"盲"来实现这一点 - 即创建并推送它们而不检查它们是否存在于中间.实际上,这意味着避免在'git tag ...'和'git push origin tag ...'序列中间使用git-fetch -tags. (2认同)