如何将git分支上的标签移动到另一个提交节点?

1173

我在主分支上创建了一个叫做v0.1的标签,就像这样:

git tag -a v0.1

但后来我发现仍然有一些更改需要合并到主分支以发布0.1版本,因此我做了这个。但现在我的v0.1标签(用便利贴笔记的类比来说)被固定在了错误的提交上。我想让它固定在主分支上最新的提交上,但它却被固定在次新的提交上。

我该如何将它移动到主分支上最新的提交?

13个回答

1574
使用-f选项来git tag
-f
--force

    Replace an existing tag with the given name (instead of failing)

你可能想要将-f-a一起使用,以强制创建一个带注释的标签,而不是非注释的标签。

示例

  1. 在推送之前,请删除任何远程标签

    git push origin :refs/tags/<tagname>
    
  2. 将标签替换为引用最新的提交

    git tag -fa <tagname>
    
  3. 将标签推送到远程仓库

    git push origin --tags
    

26
只有在您的计算机上没有推送代码时才有效。如果已经推送了代码,则最好的答案是“世界上有很多数字”,因为这可能不值得麻烦。 - Chris Huang-Leaver
73
如果您已经推送了标签,您仍然可以使用强制推送更新远程标签,命令为 git push -f origin <标签名> - rc_luke
4
如果标签引用可以快进到新的位置,您不需要使用强制推送。 - GergelyPolonkai
17
如果没有提供新的信息,这确实会移动标签消息,但在这里和文档中都没有提到。 - Twonky
28
请注意,在#3中,如果您在本地提交了任何更改,则git push origin master --tags将推送标记和“master”分支。如果您只想推送标记,请使用git push origin --tags - c32hedge
显示剩余15条评论

390

总之,如果你的远程仓库叫做origin,并且你正在master分支上工作:

git tag -d <tagname>                  # delete the old tag locally
git push origin :refs/tags/<tagname>  # delete the old tag remotely
git tag <tagname> <commitId>          # make a new tag locally
git push origin <tagname>             # push the new local tag to the remote 

描述:

  • 第1行从本地环境中删除标签。
  • 第2行从远程环境中删除标签。
  • 第3行将标签添加到不同的提交中。
  • 第4行将更改推送到远程仓库。

您还可以将第4行更改为git push origin --tags,以将所有本地标签更改/更新推送到远程仓库。

以上答案基于@eedeep的问题内容,以及Stuart GolodetzGreg Hewgill和@ben-hocking的答案,以及他们的回答下面的评论和@NateS在我的答案下原始的评论。


2
第4行用于将一个显式的单个更新标签推送到远程仓库,以防您不想更新所有标签,就像我一样。 - davenpcj
此外,如果您有一个标签和一个同名的分支(例如 1.0.0),它将会报错,显示 error: src refspec 1.0.0 matches more than one。您可以通过使用 git push origin tags/1.0.0 来明确指定要推送一个标签。 - Joseph Marikle
如果你有一个同名的标签和分支(例如 1.0.0),它会报错,显示 error: src refspec 1.0.0 matches more than one。你可以通过使用 git push origin tags/1.0.0 来明确指定推送标签。 - undefined

348

更准确地说,您需要强制添加标签,然后使用选项--tags和-f进行推送:

git tag -f -a <tagname>
git push -f --tags

4
通过添加 -f 来推送标签,这个回答完善了被接受的回答。 - Muhammad Yasirroni
3
如果您不想添加注释,请省略“-a”。 - Moot

105

使用 git tag -d <tagname> 命令删除该标签,然后在正确的提交上重新创建。


3
@eedeep:我认为公正起见,Greg的回答实际上更好。 - Stuart Golodetz
1
保持简单。删除它,再做你以前做的。 - ooolala
4
这应该是被接受的答案,因为它非常简单易懂。同时也没有过度使用-f强制命令。 - chinnychinchin
@chinnychinchin。这是一个地方,使用强制手段确实不过分。这与在合并期间说“接受我的”没有什么不同。 - Mad Physicist

96

当使用Git时,我会避免几件事情:

  1. 不使用内部知识,例如refs/tags。我尽可能只使用Git文档中记录的命令,并避免使用需要了解.git目录内部内容的东西。(也就是说,我将Git视为Git用户而不是Git开发人员。)

  2. 在没有必要的情况下使用force。

  3. 做过头。(推送分支和/或大量标签,以便在我想要的位置获取一个标签。)

因此,这是我的非暴力解决方案,用于在不了解Git内部工作原理的情况下更改标记,包括本地和远程标记。

在软件修复最终存在问题并需要更新/重新发布时,我使用它。

git tag -d fix123                # delete the old local tag
git push github :fix123          # delete the old remote tag (use for each affected remote)
git tag fix123 790a621265        # create a new local tag
git push github fix123           # push new tag to remote    (use for each affected remote)

github 是示例的远程名称,fix123 是示例的标签名称,790a621265 是示例的提交。


我认为 OP 的标签被注释了。第三行可以改成这样`git tag -a fix123 790a621265 # 创建一个新的本地注释标签` - Johan Bergens
1
我讨厌这是最好的答案。我想知道为什么它必须如此复杂?标签非常适合标记哪个提交是用于生产的,因此我经常需要更改它所附加的提交。使用一个你只需一直变基的分支目前更容易,但当环境对您的存储库内容无关紧要时(值得追求的东西),它就是多余的。 - Zyl
@Zyl:为什么要使用标签来跟踪生产HEAD?分支更适合这个任务。在生产升级时,大部分时间都可以使用分支进行快进。如果出现回归问题,可以进行硬重置分支。 - undefined
@DanielBöhmer 这就是我们在大多数代码库中最终采取的做法,但我无法告诉你有多少开发人员不理解将A合并到B并不能保证状态的相等性。沟通和知识传递在行业中往往被忽视,但它们对我们的工作方式产生的影响远远超过其他因素。 - undefined

56

我会在这里提供符合我的需求的另一种形式的该命令。
有一个标签v0.0.1.2,我想要移动它。

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

然后:

$ git push --tags --force

4
做到了这一点,这是最简单的答案。谢谢! - ehambright
FYI:这会丢失与标签相关的任何消息。 - undefined
@SaaruLindestøkke 知道了!现在太忙,没时间测试,但我想知道是否可以通过使用“-fa”而不是“-f”来修复它。 - undefined

17

将一个标签移动到不同提交的别名。

在您的示例中,要移动哈希为 e2ea1639 的提交,请执行以下操作:git tagm v0.1 e2ea1639

对于已推送的标签,请使用 git tagmp v0.1 e2ea1639

这两个别名都会保留原始日期和消息。如果您使用 git tag -d,则会丢失原始消息。

请将它们保存在您的.gitconfig文件中。

# Return date of tag. (To use in another alias)
tag-date = "!git show $1 | awk '{ if ($1 == \"Date:\") { print substr($0, index($0,$3)) }}' | tail -2 | head -1 #"

# Show tag message
tag-message = "!git show $1 | awk -v capture=0 '{ if(capture) message=message\"\\n\"$0}; BEGIN {message=\"\"}; { if ($1 == \"Date:\" && length(message)==0 ) {capture=1}; if ($1 == \"commit\" ) {capture=0}  }; END { print message }' | sed '$ d' | cat -s #"

### Move tag. Use: git tagm <tagname> <newcommit> 
tagm = "!GIT_TAG_MESSAGE=$(git tag-message $1) && GIT_COMMITTER_DATE=$(git tag-date $1) && git tag-message $1 && git tag -d $1 && git tag -a $1 $2 -m \"$GIT_TAG_MESSAGE\" #"

### Move pushed tag. Use: git tagmp <tagname> <newcommit> 
tagmp = "!git tagm $1 $2 && git push --delete origin $1 && git push origin $1 #"

14

本地删除:

git tag -d v0.1  

在远程上移除:

git push origin --delete v0.1

然后在本地重新添加并将 v0.1 推送到最近的提交:

git tag -a v0.1
git push origin --tags

13

另一种方式:

将标签移动到远程仓库。(如果需要,用其他标签替换 HEAD。)

$ git push --force origin HEAD:refs/tags/v0.0.1.2

获取更改并将其取回。

$ git fetch --tags

1
这比其他答案更“事务性”。 - Justin M. Keyes

6
如果您使用 GitHub 并想要更改提交以发布版本(例如在创建发布后发现未提交某些内容),可以使用以下操作:
git push origin :refs/tags/<tagname>

执行此命令后,GitHub将删除您的标签,使您的发布变为草稿状态。这意味着您可以重新创建发布并选择提交。您的文件和消息将被保存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接