What is git tag, How to create tags & How to checkout git remote tag(s)
Asked Answered
F

6

842

when I checkout remote git tag use command like this:

git checkout -b local_branch_name origin/remote_tag_name

I got error like this:

error: pathspec origin/remote_tag_name did not match any file(s) known to git.

I can find remote_tag_name when I use git tag command.

Faldstool answered 14/3, 2016 at 4:38 Comment(1)
git-scm.com/docs/git-tagUnaneled
L
1743

Let's start by explaining what a tag in git is

enter image description here

A tag is used to label and mark a specific commit in the history.
It is usually used to mark release points (eg. v1.0, etc.).

Although a tag may appear similar to a branch, a tag, however, does not change. It points directly to a specific commit in the history and will not change unless explicitly updated.

enter image description here


You will not be able to checkout the tags if it's not locally in your repository so first, you have to fetch the tags to your local repository.

First, make sure that the tag exists locally by doing

# --all will fetch all the remotes.
# --tags will fetch all tags as well
$ git fetch --all --tags --prune

Then check out the tag by running

$ git checkout tags/<tag_name> -b <branch_name>

Instead of origin use the tags/ prefix.


In this sample you have 2 tags version 1.0 & version 1.1 you can check them out with any of the following:

$ git checkout A  ...
$ git checkout version 1.0  ...
$ git checkout tags/version 1.0  ...

All of the above will do the same since the tag is only a pointer to a given commit.

enter image description here
origin: https://backlog.com/git-tutorial/img/post/stepup/capture_stepup4_1_1.png


How to see the list of all tags?

# list all tags
$ git tag

# list all tags with given pattern ex: v-
$ git tag --list 'v-*'

How to create tags?

There are 2 ways to create a tag:

# lightweight tag 
$ git tag v1.0

# annotated tag
$ git tag -a v1.0

The difference between the 2 is that when creating an annotated tag you can add metadata as you have in a git commit:
name, e-mail, date, comment & signature

enter image description here

How to delete tags?

Delete a local tag

$ git tag -d <tag_name>
Deleted tag <tag_name> (was 000000)

Note: If you try to delete a non existig Git tag, there will be see the following error:

$ git tag -d <tag_name>
error: tag '<tag_name>' not found.

Delete remote tags

# Delete a tag from the server with push tags
$ git push --delete origin <tag name>

How to clone a specific tag?

In order to grab the content of a given tag, you can use the checkout command. As explained above tags are like any other commits so we can use checkout and instead of using the SHA-1 simply replacing it with the tag_name

Option 1:

# Update the local git repo with the latest tags from all remotes
$ git fetch --all

# checkout the specific tag
$ git checkout tags/<tag> -b <branch>

Option 2:

Using the clone command

Since git supports shallow clone by adding the --branch to the clone command we can use the tag name instead of the branch name. Git knows how to "translate" the given SHA-1 to the relevant commit

# Clone a specific tag name using git clone 
$ git clone <url> --branch=<tag_name>

git clone --branch=

--branch can also take tags and detaches the HEAD at that commit in the resulting repository.


How to push tags?

git push --tags

To push all tags:

# Push all tags
$ git push --tags 

Using the refs/tags instead of just specifying the <tagname>.

Why?

  • It's recommended to use refs/tags since sometimes tags can have the same name as your branches and a simple git push will push the branch instead of the tag

To push annotated tags and current history chain tags use:

git push --follow-tags

This flag --follow-tags pushes both commits and only tags that are both:

  • Annotated tags (so you can skip local/temp build tags)
  • Reachable tags (an ancestor) from the current branch (located on the history)

enter image description here

From Git 2.4 you can set it using configuration

$ git config --global push.followTags true

Cheatsheet: enter image description here


Lumpy answered 14/3, 2016 at 4:49 Comment(7)
nice. git checkout A. what is A? How did you create A?Telephonist
@Honey A is a commit hashEvangelical
@GiovanniLovato The flow chart is a third party one. The link to the image is backlog.com/git-tutorial/img/post/stepup/… which is from this page backlog.com/git-tutorial/stepup/stepup4_1.html of the website called Git Beginner's Guide for Dummies (backlog.com).Waxbill
It's worth noting that git checkout tags/<tag_name> -b <branch_name> does require the -b <branch_name>. git checkout tags/<tag_name> gave me a detached head. As per this article about detached head, you avoid a detached head by temporarily creating and deleting a branch. This is quite an alien work flow. Clearly I as a git user need to get used to creating and deleting branches for fun and profit.Cruickshank
Excellent answer, but it doesn't address whether you can add multiple tags to a single commit.Crosspiece
Should "hexadecimal version names" instead be "Git commit ID (a 40-digit SHA-1 hash)"?Crosspiece
Came here looking for 'How to checkout git tag'. While I like most of the pretty pictures, this answer (in line with the question title before being edited to suit the post) would be better imo by removing the top cartoon and replacing it with a text version of the cheat sheet as a tl/dr;.Andersen
S
214

(This answer took a while to write, and codeWizard's answer is correct in aim and essence, but not entirely complete, so I'll post this anyway.)


There is no such thing as a "remote Git tag". There are only "tags". I point all this out not to be pedantic,1 but because there is a great deal of confusion about this with casual Git users, and the Git documentation is not very helpful2 to beginners. (It's not clear if the confusion comes because of poor documentation, or the poor documentation comes because this is inherently somewhat confusing, or what.)

There are "remote branches", more properly called "remote-tracking branches", but it's worth noting that these are actually local entities. There are no remote tags, though (unless you (re)invent them). There are only local tags, so you need to get the tag locally in order to use it.

The general form for names for specific commits—which Git calls references—is any string starting with refs/. A string that starts with refs/heads/ names a branch; a string starting with refs/remotes/ names a remote-tracking branch; and a string starting with refs/tags/ names a tag. The name refs/stash is the stash reference (as used by git stash; note the lack of a trailing slash).

There are some unusual special-case names that do not begin with refs/: HEAD, ORIG_HEAD, MERGE_HEAD, and CHERRY_PICK_HEAD in particular are all also names that may refer to specific commits (though HEAD normally contains the name of a branch, i.e., contains ref: refs/heads/branch). But in general, references start with refs/.

One thing Git does to make this confusing is that it allows you to omit the refs/, and often the word after refs/. For instance, you can omit refs/heads/ or refs/tags/ when referring to a local branch or tag—and in fact you must omit refs/heads/ when checking out a local branch! You can do this whenever the result is unambiguous, or—as we just noted—when you must do it (for git checkout branch).

It's true that references exist not only in your own repository, but also in remote repositories. However, Git gives you access to a remote repository's references only at very specific times: namely, during fetch and push operations. You can also use git ls-remote or git remote show to see them, but fetch and push are the more interesting points of contact.

Refspecs

During fetch and push, Git uses strings it calls refspecs to transfer references between the local and remote repository. Thus, it is at these times, and via refspecs, that two Git repositories can get into sync with each other. Once your names are in sync, you can use the same name that someone with the remote uses. There is some special magic here on fetch, though, and it affects both branch names and tag names.

You should think of git fetch as directing your Git to call up (or perhaps text-message) another Git—the "remote"—and have a conversation with it. Early in this conversation, the remote lists all of its references: everything in refs/heads/ and everything in refs/tags/, along with any other references it has. Your Git scans through these and (based on the usual fetch refspec) renames their branches.

Let's take a look at the normal refspec for the remote named origin:

$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$ 

This refspec instructs your Git to take every name matching refs/heads/*—i.e., every branch on the remote—and change its name to refs/remotes/origin/*, i.e., keep the matched part the same, changing the branch name (refs/heads/) to a remote-tracking branch name (refs/remotes/, specifically, refs/remotes/origin/).

It is through this refspec that origin's branches become your remote-tracking branches for remote origin. Branch name becomes remote-tracking branch name, with the name of the remote, in this case origin, included. The plus sign + at the front of the refspec sets the "force" flag, i.e., your remote-tracking branch will be updated to match the remote's branch name, regardless of what it takes to make it match. (Without the +, branch updates are limited to "fast forward" changes, and tag updates are simply ignored since Git version 1.8.2 or so—before then the same fast-forward rules applied.)

Tags

But what about tags? There's no refspec for them—at least, not by default. You can set one, in which case the form of the refspec is up to you; or you can run git fetch --tags. Using --tags has the effect of adding refs/tags/*:refs/tags/* to the refspec, i.e., it brings over all tags (but does not update your tag if you already have a tag with that name, regardless of what the remote's tag says Edit, Jan 2017: as of Git 2.10, testing shows that --tags forcibly updates your tags from the remote's tags, as if the refspec read +refs/tags/*:refs/tags/*; this may be a difference in behavior from an earlier version of Git).

Note that there is no renaming here: if remote origin has tag xyzzy, and you don't, and you git fetch origin "refs/tags/*:refs/tags/*", you get refs/tags/xyzzy added to your repository (pointing to the same commit as on the remote). If you use +refs/tags/*:refs/tags/* then your tag xyzzy, if you have one, is replaced by the one from origin. That is, the + force flag on a refspec means "replace my reference's value with the one my Git gets from their Git".

Automagic tags during fetch

For historical reasons,3 if you use neither the --tags option nor the --no-tags option, git fetch takes special action. Remember that we said above that the remote starts by displaying to your local Git all of its references, whether your local Git wants to see them or not.4 Your Git takes note of all the tags it sees at this point. Then, as it begins downloading any commit objects it needs to handle whatever it's fetching, if one of those commits has the same ID as any of those tags, git will add that tag—or those tags, if multiple tags have that ID—to your repository.

Edit, Jan 2017: testing shows that the behavior in Git 2.10 is now: If their Git provides a tag named T, and you do not have a tag named T, and the commit ID associated with T is an ancestor of one of their branches that your git fetch is examining, your Git adds T to your tags with or without --tags. Adding --tags causes your Git to obtain all their tags, and also force update.

Bottom line

You may have to use git fetch --tags to get their tags. If their tag names conflict with your existing tag names, you may (depending on Git version) even have to delete (or rename) some of your tags, and then run git fetch --tags, to get their tags. Since tags—unlike remote branches—do not have automatic renaming, your tag names must match their tag names, which is why you can have issues with conflicts.

In most normal cases, though, a simple git fetch will do the job, bringing over their commits and their matching tags, and since they—whoever they are—will tag commits at the time they publish those commits, you will keep up with their tags. If you don't make your own tags, nor mix their repository and other repositories (via multiple remotes), you won't have any tag name collisions either, so you won't have to fuss with deleting or renaming tags in order to obtain their tags.

When you need qualified names

I mentioned above that you can omit refs/ almost always, and refs/heads/ and refs/tags/ and so on most of the time. But when can't you?

The complete (or near-complete anyway) answer is in the gitrevisions documentation. Git will resolve a name to a commit ID using the six-step sequence given in the link. Curiously, tags override branches: if there is a tag xyzzy and a branch xyzzy, and they point to different commits, then:

git rev-parse xyzzy

will give you the ID to which the tag points. However—and this is what's missing from gitrevisionsgit checkout prefers branch names, so git checkout xyzzy will put you on the branch, disregarding the tag.

In case of ambiguity, you can almost always spell out the ref name using its full name, refs/heads/xyzzy or refs/tags/xyzzy. (Note that this does work with git checkout, but in a perhaps unexpected manner: git checkout refs/heads/xyzzy causes a detached-HEAD checkout rather than a branch checkout. This is why you just have to note that git checkout will use the short name as a branch name first: that's how you check out the branch xyzzy even if the tag xyzzy exists. If you want to check out the tag, you can use refs/tags/xyzzy.)

Because (as gitrevisions notes) Git will try refs/name, you can also simply write tags/xyzzy to identify the commit tagged xyzzy. (If someone has managed to write a valid reference named xyzzy into $GIT_DIR, however, this will resolve as $GIT_DIR/xyzzy. But normally only the various *HEAD names should be in $GIT_DIR.)


1Okay, okay, "not just to be pedantic". :-)

2Some would say "very not-helpful", and I would tend to agree, actually.

3Basically, git fetch, and the whole concept of remotes and refspecs, was a bit of a late addition to Git, happening around the time of Git 1.5. Before then there were just some ad-hoc special cases, and tag-fetching was one of them, so it got grandfathered in via special code.

4If it helps, think of the remote Git as a flasher, in the slang meaning.

Sweeten answered 14/3, 2016 at 7:10 Comment(2)
Great writeup. One tiny nit: git fetch will only fetch the remote's tags given the --tags arg.Haskel
@cweekly: the behavior of --tags, --no-tags, and default is actually quite tricky. The default is to bring in tags that you don't have that are in the commits you're bringing in. (See the Jan 2017 edit.) But there are glitches here as well, and modern Git is having its --tags/--no-tags handling code revised yet again, which will probably lead to yet more special corner cases.Sweeten
C
46

In order to checkout a git tag , you would execute the following command

git checkout tags/tag-name -b branch-name

eg as mentioned below.

 git checkout tags/v1.0 -b v1.0-branch

To find the remote tags:

git ls-remote --tags origin

Create a tag with the given tag message

git tag <tag_name> -a -m "tag message"

To Push a single tag to remote

git push origin <tag_name>

Push all tags to remote

git push origin --tags
Czarist answered 7/4, 2020 at 12:36 Comment(0)
W
5

When I want the code at a tag, I may not want to create a branch (typically, I only need a full branch if I'll be hotfixing it).

To temporarily rewind your branch to the code at the tag, do this:

git reset --hard tags/1.2.3

I can use it briefly as needed, then get back to HEAD of the branch when I'm done, with a simple git pull.

Wiesbaden answered 17/11, 2021 at 19:24 Comment(0)
F
1

To get the specific tag code try to create a new branch add get the tag code in it. I have done it by command : $git checkout -b newBranchName tagName

Fulminant answered 25/7, 2019 at 12:6 Comment(0)
P
1

This is bit out of context but in case you are here because you want to tag a specific commit like i do

Here's a command to do that :-

Example:

git tag -a v1.0 7cceb02 -m "Your message here"

Where 7cceb02 is the beginning part of the commit id.

You can then push the tag using git push origin v1.0.

You can do git log to show all the commit id's in your current branch.

Parthenope answered 15/1, 2021 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.