【问题标题】:Move tag one commit ahead将标记向前移动一个提交
【发布时间】:2014-11-09 00:53:25
【问题描述】:

我有一个只有一个分支的存储库 (master)。我是我的 repo 的唯一贡献者。

我最近在本地添加了一个tag,并推送到了 GitHub。在做出我认为是最后一次必要的提交之后,但现在我意识到我应该再做一次更改/提交。

所以我有的是:

commit 124
commit 125
commit 126 <-- tag v1.0
commit 127

我想将v1.0 标签移动到下一个提交,即:127,本地和 GitHub 中。

我该怎么做?

【问题讨论】:

  • 一旦你推送它们,你就不能修改历史(或标签),好吧,你实际上可以,但是你会重写历史,这很糟糕(TM)。处理它并创建一个新的版本标签,比如 v1.0.1 什么的。
  • @Gabriel,不,这相当于同一件事。 KurzedMetal 建议您保留旧标签并添加一个 new 标签,可能是v1.0.1。我同意这是正确的方法。
  • @Gabriel,建议不是“Git 不能移动标签,所以你必须通过删除标签并再次添加它来伪造它”。它是“修改已发布的标签通常是一个坏主意,可能会导致问题,所以你应该避免这样做”。
  • 我是我的 repo 的唯一贡献者。目前可能,但如果其他人有权访问您的存储库(例如,如果它是公开的),那么人们可能已经分叉或克隆了它。
  • @Jubobs:到目前为止还没有分叉(Github 让你知道),我怀疑是否有任何克隆,但这是一个公平的观点。

标签: git github version versioning commit


【解决方案1】:

通常不鼓励移动标签,因为由于 Git 的高度分布式特性,它可能会导致问题。考虑:

  • 您在提交时推送标签v1.0 abcd123
  • 你的朋友,叫他弗雷德,去取东西
  • Fred 现在在 abcd123 上有一个本地 v1.0 标签
  • 您将标签v1.0 移动到提交cccc222 并推送
  • 可能会发生以下情况:
    • Fred 获取,但服务器上的 v1.0 标记与他本地的 v1.0 标记不匹配,因此 Fred 必须手动修复此冲突,即使他没有采取任何措施来导致它
    • Fred 使用--tags 选项推送以添加他创建的新标签some-tag;这个推送被服务器拒绝了,因为他本地的v1.0标签和服务器的v1.0标签不一致

如果有两个以上的开发人员,这会变得更加复杂;如果即使一个人没有采取步骤更新他或她的本地标签,您也可以获得trouble down the line

如果您仍然确定要移动标签(也许这是一个开发人员项目,或者您确定没有人获取标签,或者您准备与所有其他开发人员进行沟通,并且确保他们更新他们的本地标签)你可以这样做:

git tag -a -f v1.0 <new-commit-hash>
git push --tags --force

应鼓励其他开发人员删除其本地标签副本并获取新标签:

git tag -d v1.0
git fetch --tags

【讨论】:

  • 重要提示:git push --tags --force 将强制更新源存储库上的本地存储库中的每个标签
【解决方案2】:

您是否曾经去过一个读书俱乐部,那里的会员并不都使用相同版本的“本周图书”?这是一场噩梦,对吧?移动标签基本上会让你处于同样的境地。

如果您将存储库视为记录项目进度的书籍,您可以将标签视为章节标题

在分享标签后将标签移动到不同的提交就像告诉你所有的书友们

你们知道吗,伙计们?到目前为止我们一直在使用的这本书的版本现在已经过时了,因为我已经下令现在开始第 8 章,而不是从第 126 页开始,而是从第 128 页开始。

不好。移动标签是重写历史的一种形式,您不应该重写已共享的历史。这是惹恼合作者的最可靠方法。另外,你写

我是我的 repo 的唯一贡献者 [...]

目前可能是这样,但如果您以外的其他人有权访问您的 GitHub 存储库(例如,如果它是公开的),他们中的一些人可能已经分叉或克隆了它(尽管有一个 way 可以找到),如果你改写历史,你就有惹恼他们的风险。


如果您 100% 确定要移动该标签,Git 确实允许您这样做。在这里,你可以使用

git tag --force v1.0 <ID-of-commit-127>

然后你将不得不强制推送该标签,使用

git push --force --tags

但是,在继续之前三思而后行...

附录 (2018/09/26)

我觉得有必要重新审视我的答案...

多年来,一些人在 cmets 中反对我的禁令,即不要移动已发布的标签。当然,这条建议是根据上下文而不是通用的;我不怀疑存在移动已发布标签的好案例。但是,我坚信,作为一般规则,移动已发布标签的决定应经过深思熟虑并格外小心。

我想到了一个最近的例子。 Go 1.11 添加了对 module system 的实验性支持,该支持严重依赖 Git 标签进行版本控制。在已发布(比如在 GitHub 上)的 Go 模块中移动标签会产生灾难性的后果。

这样做,你会破坏你(模块作者)和你的用户(那些依赖你的模块的人)之间建立的合同,因为你会否定 Go 的模块系统打算提供的保证:

模块记录精确的依赖要求并创建可重现的构建。

这是惹恼人们的一种肯定方式。

这个例子可能足以让您相信,至少在某些情况下,您不应该盲目地移动已发布的标签。我休息一下。

【讨论】:

  • 这个概括太笼统了。想象一个打包系统,它抓取一大堆项目的快照并创建它们的捆绑包。项目作者可以使用移动标签来传达他们建议包含的修订版本。历史被覆盖的分支比 'git fetch --tags' 更令人头疼。现在,这个用例中缺少的一点是 git 可以保留标签的历史记录,即同名的后续标签可能会影响以前的版本,但它们仍然在历史记录中可见。
  • 我是那种只关心工具有用的人,而不是它的用途。
  • @AttilaLendvai 当然,但是一个工具的意义在于它的用途:)
  • 哈哈! “泪水池”——那一定是一本关于 Git 的书,对吧!?
  • 此答案描述了一种使用标签的方式以及在使用标签时移动标签的方式,这种方式会导致问题。但它错过了 git 中标签的一般用途。您可以随意创建一个名为“FAV”的标签,而不是“1.1.2”。相同的提交,两个标签。移动 FAV 很有意义。移动 1.1.2 不会。更深入地了解您正在做什么,以及您正在使用的工具在更深层次上做什么。然后,您可以从这样的答案中获取有用的信息(移动标签的 git 命令是什么?),然后扔掉其余的(其他所有内容。)
【解决方案3】:

您也可以删除标签然后重新创建它,这不需要重写历史记录。
(没有push --force

删除本地和远程

git tag -d <tag_name>
git push origin :refs/tags/<tag_name>

重新创建

git tag <tag_name>
git push --tags

【讨论】:

  • 对于已经将标记提交拉到其本地计算机(或分叉远程)的任何人,它仍然会导致冲突。您的答案实际上与之前给出的答案相同。移动或删除标签确实会更改历史记录,因为标签本质上是提交编号的“别名”。您已更改标签引用的提交编号。更糟糕的是,正如其他更详细的答案所指出的那样,其他人的本地仓库中的标签现在引用了与您的本地仓库不同的提交,以及更改后的远程仓库。这会导致冲突和混乱。
  • 虽然您说 结果 与移动标签没有任何变化是正确的,但我想说删除对于您的意图不太明确。
猜你喜欢
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多