移动标签1提前提交

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

我最近添加了一个 tag,它既可以在本地使用,也可以推送到 GitHub。在做了我认为是最后一次必要的承诺之后,但现在我意识到我应该再做一次更改/承诺。

所以我得到的是:

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

我想将 v1.0标记移动到下一个提交,即: 127,在本地和 GitHub 中都是如此。

我该怎么做?

58636 次浏览

Moving tags is generally discouraged since it can cause problems due to Git's highly distributed nature. Consider:

  • You push tag v1.0 on commit abcd123
  • Your buddy, call him Fred, fetches
  • Fred now has a local v1.0 tag on abcd123
  • You move tag v1.0 to commit cccc222 and push
  • The following things can happen:
    • Fred fetches, but the v1.0 tag on the server doesn't match his local v1.0 tag, so Fred has to manually fix this conflict, even though he didn't do anything to cause it
    • Fred pushes with the --tags option to add a new tag some-tag that he created; this push is rejected by the server because his local v1.0 tag and the server's v1.0 tag disagree

With more than two developers this gets much more complicated; if even one person doesn't take the step to update his or her local tag you can get trouble down the line.

If you're still sure that you want to move the tag (perhaps this is a one developer project, or you're otherwise sure that nobody has fetched the tag, or you're prepared to communicate with all other developers and make sure that they update their local tags) you can do something like this:

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

Other developers should be encouraged to delete their local copy of the tag and fetch the new one:

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

Have you ever been to a book club where members do not all use the same edition of the "book of the week"? It's a nightmare, right? Moving a tag would essentially put you in the same situation.

If you think of your repository as a book that chronicles progress in your project, you can think of a tag as a chapter heading.

enter image description here

Moving a tag to a different commit after sharing it is like telling all your book-club buddies

You know what, guys? The edition of the book we've all been using so far is now obsolete, because I have solely decreed that chapter 8 shall now start, not on page 126, but on page 128.

Not good. Moving a tag is a form of history rewriting, and you shouldn't rewrite history that has been shared. It's the surest way to piss your collaborators off. Besides, you write

I'm the only contributor to my repo [...]

That may be true for now, but if other people than you have access to your GitHub repository (e.g. if it's public), some of them may already have forked or cloned it (although there is a way to find out), and you run the risk of pissing them off if you rewrite history.


If you're 100% sure that you want to move that tag anyway, Git does allow you to do it. Here, you could use

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

and then you would have to force push that tag, using

git push --force --tags

But again, think twice before going ahead...

Addendum (2018/09/26)

I feel the need to revisit my answer...

Over the years, some people have objected in the comments to my injunction not to move an already published tag. Of course, this piece of advice is contextual rather than universal; I don't doubt that good cases for moving a published tag exist. However, I stand firm in the belief that, as a general rule, the decision to move a published tag should be made deliberately and with extreme care.

One recent example comes to mind. Go 1.11 added experimental support for a module system that relies heavily on Git tags for versioning. Moving a tag in a Go module that has been published (on GitHub, say) would have disastrous consequences.

By doing so, you would break the contract established between you (the module author) and your users (those who depend on your module), because you would negate the guarantees that Go's module system intends to provide:

Modules record precise dependency requirements and create reproducible builds.

That's one sure way to piss people off.

This example may be enough to convince you that, at least in some cases, you shouldn't mindlessly move published tags. I rest my case.

You could also delete the tag and then recreate it, this does not require a rewrite of the history.
(No push --force)

Delete local and remote

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

Recreate

git tag <tag_name>
git push --tags