97

I have a repository with only one branch (master). I'm the only contributor to my repo.

I've recently added a tag, both locally and pushed to GitHub. After making what I though was the last necessary commit, but now I realize I should have made one more change/commit.

So what I have is:

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

and I want to move the v1.0 tag to the next commit, ie: 127, both locally and in GitHub.

How can I do that?

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Gabriel
  • 40,504
  • 73
  • 230
  • 404
  • 3
    You can't modify history (or tags) once you push them, well, you actually can, but you'd rewriting history, which is bad(TM). Deal with it and create a new version tag, like v1.0.1 or something. – KurzedMetal Sep 15 '14 at 13:19
  • So you say I should just remove this tag, make the commit and then create it again? That's what I was trying to avoid, but if there's no other option... – Gabriel Sep 15 '14 at 13:23
  • 2
    @Gabriel, no, that would amount to the same thing. KurzedMetal is suggesting that you leave the old tag in place and add a *new* tag, perhaps `v1.0.1`. I agree that this is the correct approach. – ChrisGPT was on strike Sep 15 '14 at 13:26
  • @Chris that won't work. The commit I forgot is precisely the one that marks the version number within the code. What do you mean by "that would amount to the same thing"? What I described would solve my issue although in a complicated way I was traying to avoid. – Gabriel Sep 15 '14 at 13:37
  • 2
    @Gabriel, the recommendation isn't "Git can't move a tag, so you've got to fake it by removing the tag and adding it again". It's "modifying published tags is generally a bad idea and can cause problems, so you should avoid doing it". – ChrisGPT was on strike Sep 15 '14 at 13:50
  • 1
    *I'm the only contributor to my repo*. For now, maybe, but if other people have access to your repository (e.g. if it's public), people may have already forked or cloned it. – jub0bs Sep 15 '14 at 14:12
  • 3
    @Jubobs: no forks so far (Github lets you know) and I doubt there are any clones, but that's a fair point. – Gabriel Sep 15 '14 at 14:14

3 Answers3

183

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.

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 12
    this is too broad a generalization. imagine a packaging system that grabs a snapshot of a whole bunch of projects and creates a bundle of them. project authors can use a moving tag to communicate which revision they propose for inclusion. branches with overwritten history pose much more headache than a 'git fetch --tags'. now, what's somewhat missing from this use-case is that git could keep a history of tags, i.e. a later tag of the same name could shadow a former version, but all of them still be visible in history. – Attila Lendvai Feb 10 '16 at 11:25
  • 1
    @AttilaLendvai What you suggest goes against what Git tags are meant for. – jub0bs Apr 12 '16 at 10:23
  • 24
    i'm the kind of guy who only cares about what a tool is *useful* for, not what it was meant for. – Attila Lendvai Apr 13 '16 at 13:55
  • 2
    @AttilaLendvai Sure, but what a tool was meant for conditions what it's useful for :) – jub0bs Apr 13 '16 at 14:02
  • 1
    We see the pattern of a _moving tag_ in symbols such as HEAD for repos, and _latest_ for paths/urls and versions etc.These are constantly being moved and updated. Further in daily speech we always say things like "_Is this the freshest coffee you have?_", or "_Is this the latest version of X?_" etc...I have no problem with a _moving tag_ and I don't think anyone else should either, if there is an understanding that this is what it is for. Design your workflows and infrastructure accordingly. – dharmatron Nov 29 '17 at 20:35
  • @dharmatron HEAD isn't a tag and is meant to move. Relying on a latest tag can be convenient, but can also break things from under you. The same caveat goes with using `latest` tags with Docker. – jub0bs Jan 25 '18 at 13:47
  • 1
    @Jubobs I think you may be getting caught up a little in semantics. Generic terms such as "latest" are seen everywhere and these are understood to be moving targets. Specific terms such as v.1.0.9 are not intended to move for obvious reasons. Make the platform do what you need it to (heh-heh like a jazz musician does with music), not what rote intellectual verbage dictates, often without full consideration of the extent to which a mechanism might be used. Humans are creative and the organic evolution of "rules" is what leads to 'convention'. Barista, a cup of your "freshest" (latest) please... – dharmatron Feb 12 '18 at 21:55
  • 6
    Ha ha! "The pool of tears" - that's got to be a book on Git, right!? – Steve Eynon May 28 '18 at 15:08
  • 1
    I have seen at least one big project which uses moving-tags as a form of collaboration. The most important thing is that all the main devs agree with what's going on, and that any particularly egregious departures from commonly-accepted best-practices are documented somewhere for newcomer developers. – JamesTheAwesomeDude Jul 17 '18 at 18:03
  • @JamesTheAwesomeDude That's fine, as long as everyone is "on the same page", to continue the book-club analogy :p – jub0bs Jul 18 '18 at 08:50
  • 5
    This answer describes one way to use tags and the way moving tags when using them that one way causes problems. But it misses the general utility of tags in git. You're free to make a tag called "FAV" instead of "1.1.2". Same commit, two tags. Moving FAV makes a lot of sense. Moving 1.1.2 does not. Understand what you're doing at a deeper level, and what the tools you're using do at a deeper level. Then you can take the useful bits from answers like this (what are the git commands to move a tag?) and throw away the rest (everything else.) – 6cef Sep 27 '18 at 18:35
  • 1
    It seems we loose the annotation if we move without using the "-a" option. Maybe update this top-voted answer? I see that the next answer has `git tag -a -f ...` Or am I missing something? – hansfn Sep 27 '19 at 08:34
  • 1
    I am glad that this feature exists. For example, say someone makes changes, adds them, creates a tag and pushes it then seconds later they realize they forgot to commit between the add and tag creation... Speaking of a friend I know, of course... No one knows about the tag or cares about it. I think that this is a good use for this feature... But in general I agree that it is bad practice to move tags that are ***being used***. In smaller, less used systems or ones where everyone gets bent out of shape over "changing software versions" this is a nice tool to have! – Chad May 16 '23 at 16:40
28

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
Emmanuel DURIN
  • 4,803
  • 2
  • 28
  • 53
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
  • Important note: `git push --tags --force` will force update **every tag in your local repository** on the origin repo! – Ogre Psalm33 Sep 08 '20 at 18:51
12

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
Jonas Marty
  • 348
  • 3
  • 13
  • 2
    It still causes a conflict for anyone who has already pulled the tagged commit to their local machine (or forked remote). Your answer is actually the same as the answers previously given. Moving or deleting tags does change history, as a tag is essentially an "alias" for a commit number. You have changed the commit number your tag references. Worse, as pointed out in other more detailed answers, the tag in someone else's local repo now references a different commit than your local repo, and the altered remote repo. This causes conflicts and confusion. – SherylHohman Jan 24 '19 at 15:02
  • 1
    While you're correct to say there's no change in the _outcome_ vs moving the tag, I'd say deleting is LESS explicit about what your intention was. – Scott Prive Aug 16 '19 at 15:29