Why is my tag not specified when placing an order using the Git GUI?

I have a local Git repository that contains three annotated tags: v0.1.0 , v0.1.1 and v0.1.2 .

When I view the project history using gitk (repository -> visualize the main history), I can see every tag assigned to the correct commit.

Gitk project history

However, when I try to check my tags in the Git GUI (Branch โ†’ Checkout ... โ†’ Tags), the tag for v0.1.1 does not appear.

Git GUI Tag List

When I went to check every tag in gitk, I noticed that the details of the tag are slightly different. Details for v0.1.0 and v0.1.2 designated them as type commit , and the tag for v0.1.1 was specified as type tag .

Details for the v0.1.1 tag

It is worth noting that I rewrote the history of this tag. To correct a typo in the description of my tag, I edited my tag message using git tag <tag name> <tag name> -f -m "<new message>" .

Why can't I see the v0.1.1 tag when checking with the Git GUI? Why does it look like a type tag ?

+1
source share
2 answers

Tags point to any object in the git repository. If your tag type is โ€œtag,โ€ then you have a tag pointing to another tag.

This cannot happen with light tags because they literally just point to a commit, slightly less than the name of the branch. However, if you use annotated tags, then the tags themselves are objects (like commits) with their own message, author, etc.

Of course, as you described in your comment , this is exactly what happened. Following the advice found in How do you rename a git tag? , you did the following:

 # avoid this... git tag new old 

Since old was an annotated tag, the target of the new tag will be the old tag, not the commit it pointed to.

If you want to rename the annotated tag, you should use

 git tag -a new old^{} 

old^{} will dereference the tag recursively until an object without tags is found (in our case, a commit) and use that as the target for new .


To clarify again: let's say you have a repo ... oh, like this one: https://github.com/cyborgx37/sandbox/releases

In this repo, you create an annotated tag, for example:

 > git tag -m "Version 0.1-beat" v0.1 

Oh, shoot ... you mistakenly wrote "beta" and also decided that you want the tag name to be v0.1-b . Since this has already been published, you decided to do a reasonable thing and just create a new tag. Following the tips you found on the Internet , you create the tag that you really wanted (I added __tag for reasons that will become clear) by copying the first tag:

 > git tag -m "Version 0.1-beta" v0.1-b__tag v0.1 

Only these are annotated tags, which means that they are real objects. Therefore, when you created v0.1-b__tag , you actually pointed it to v0.1 . You can see the result with cat-file and show .

Here v0.1 :

 > git cat-file -p v0.1 object 5cf4de319291579d4416da8e0eba8a2973f8b0cf type commit tag v0.1 tagger JDB < jd@domain.com > 1521058797 -0400 Version 0.1-beat 
 > git show v0.1 tag v0.1 Tagger: JDB < jd@domain.com > Date: Wed Mar 14 16:19:57 2018 -0400 Version 0.1-beat commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master) Author: JDB < jd@domain.com > Date: Tue Oct 10 12:17:00 2017 -0400 add gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42d9955 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +file.txt 

Note that v0.1-b__tag differs both in type and in its history:

 > git cat-file -p v0.1-b__tag object 889b82584b2294486f4956dfea17b05e6224fb7f type tag tag v0.1-b__tag tagger JDB < jd@domain.com > 1521059058 -0400 Version 0.1-beta 
 > git show v0.1-b__tag tag v0.1-b__tag Tagger: JDB < jd@domain.com > Date: Wed Mar 14 16:24:18 2018 -0400 Version 0.1-beta tag v0.1 Tagger: JDB < jd@domain.com > Date: Wed Mar 14 16:19:57 2018 -0400 Version 0.1-beat commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master) Author: JDB < jd@domain.com > Date: Tue Oct 10 12:17:00 2017 -0400 add gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42d9955 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +file.txt 

Apparently, the git GUI is pretty selective about what types of objects can be checked (commits, not tags), so it ignores your tag pointing to another tag.

If you use the git tag -a new old^{} approach suggested above, you can avoid the drama and get what you need first. I will create a new v0.1-b__commit tag that points to v0.1 commit, and not to v0.1 directly:

 > git tag -m "Version 0.1-beta" v0.1-b__commit v0.1^{} 
 > git cat-file -p v0.1-b__commit object 5cf4de319291579d4416da8e0eba8a2973f8b0cf type commit tag v0.1-b__commit tagger JDB < jd@domain.com > 1521059039 -0400 Version 0.1-beta 
 > git show v0.1-b__commit tag v0.1-b__commit Tagger: JDB < jd@domain.com > Date: Wed Mar 14 16:23:59 2018 -0400 Version 0.1-beta commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1-b__commit, tag: v0.1, origin/master) Author: JDB < jd@domain.com > Date: Tue Oct 10 12:17:00 2017 -0400 add gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42d9955 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +file.txt 
+4
source

I usually donโ€™t use any of the Git GUIs, so I canโ€™t answer the details depending on the GUI, but your observation that the difference between annotated tags and light tags is blurring, and yes, there should be some warning in some answers to How do you rename a Git tag?

When I went to check every tag in gitk, I noticed that the details of the tag are slightly different. Details for v0.1.0 and v0.1.2 designated them as type commit , and the tag for v0.1.1 was specified as a type tag. I suspect this may be causing my problem ...

Let me clarify the difference between the two and talk about tag mechanisms.

In Git, the "true name" of any actual commit is the hash identifier of the commit. Hash identifiers are long, ugly, impossible to remember strings, such as ca5728b6... , displayed in one of your GUI panels. I created a new, empty repository and made one commit in it:

 $ git init Initialized empty Git repository in ... $ echo for testing tags > README $ git add README $ git commit -m initial [master (root-commit) a912caa] initial 1 file changed, 1 insertion(+) create mode 100644 README $ git rev-parse HEAD a912caa83de69ef8e5e3e06c3d74b6c409068572 

This identifies the commit, and we can see that with git cat-file -t , which tells us the type of each internal Git object:

 $ git cat-file -t a912c commit 

You can shorten large ugly identifiers as long as the abbreviation is unique and has at least four letters. one

In any case, now let's make two different tags, pointing to the same commit:

 $ git tag -m "an annotated tag" annotag $ git tag lightweight 

and use git for-each-ref to check them:

 $ git for-each-ref a912caa83de69ef8e5e3e06c3d74b6c409068572 commit refs/heads/master dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 tag refs/tags/annotag a912caa83de69ef8e5e3e06c3d74b6c409068572 commit refs/tags/lightweight 

An annotated tag has a different hash identifier than a light tag.

The trick here is that the light tag only creates the name in the reference database, in this case refs/tags/lightweight . The names are in the identifiers of the hash records of the control database, so this one stores the hash identifier of our single commit.

An annotated tag, on the other hand, exists as an object of a real repository, so we can check its type and see its contents using git cat-file :

 $ git cat-file -t dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 tag $ git cat-file -p dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 | sed 's/@/ /' object a912caa83de69ef8e5e3e06c3d74b6c409068572 type commit tag annotag tagger Chris Torek <chris.torek gmail.com> 1521059496 -0700 an annotated tag 

Please note that the annotated tag object in the repository database with the hash identifier key contains the object data and contains the commit hash identifier. In fact, there is also a "light weight" tag with the name refs/tags/annotag pointing to the object of the annotated tag. But since it points to an annotated tag object, it is treated as an annotated tag.

When you create a new tag, you can point it to any existing object. Let's take a look at the objects associated with single commit:

 $ git cat-file -p HEAD | sed 's/@/ /' tree 4d73be7092200632865da23347ba0af4ac6c91f7 author Chris Torek <chris.torek gmail.com> 1521053169 -0700 committer Chris Torek <chris.torek gmail.com> 1521053169 -0700 initial 

This commit object refers to a tree object that we can verify:

 $ git cat-file -p 4d73be7092200632865da23347ba0af4ac6c91f7 100644 blob 938c7cff87a9b753ae70d91412d3ead5c95ef932 README 

and the tree points to a blob object, which we can also check:

 $ git cat-file -p 938c7cff87a9b753ae70d91412d3ead5c95ef932 for testing tags 

which is the contents of the README . Let the tag:

 $ git tag the-file 938c7cff87a9b753ae70d91412d3ead5c95ef932 

and check its type:

 $ git cat-file -t the-file blob 

This is not the usual use of a tag, but it is allowed. Try making an easy tag for an annotated tag:

 $ git tag maybe-light annotag $ git cat-file -t maybe-light tag $ git cat-file -p maybe-light | sed 's/@/ /' object a912caa83de69ef8e5e3e06c3d74b6c409068572 type commit tag annotag tagger Chris Torek <chris.torek gmail.com> 1521059496 -0700 an annotated tag 

This maybe-light tag points to an annotated tag object that belongs to the annotag annotated tag. Is maybe-light an annotated tag? It depends on your point of view, right? I would say that this is and is not: it is a light tag pointing to an annotated tag, but it is not a light tag that has the same name as the object of the annotated tag, which claims directly inside the object that will / belongs to - to annotag . But I would also say that in a sense, annotag is both a lightweight and an annotated tag: it is a lightweight tag that gives the object identifier of the annotated tag. They use the same name, so I would call it an โ€œannotated tagโ€ and designate refs/tags/annotag as the tag name, just as refs/tags/maybe-light is the tag name.

In any case, we can also make more annotated tags that point to any of these objects. If we make an annotated tag that points to another annotated tag, we end up with two annotated tag objects:

 $ git tag -m "also annotated" anno2 $ git for-each-ref a912caa83de69ef8e5e3e06c3d74b6c409068572 commit refs/heads/master 060527046d210f0219170cdc6354afe4834ddc6d tag refs/tags/anno2 dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 tag refs/tags/annotag a912caa83de69ef8e5e3e06c3d74b6c409068572 commit refs/tags/lightweight dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 tag refs/tags/maybe-light 938c7cff87a9b753ae70d91412d3ead5c95ef932 blob refs/tags/the-file 

You can see from this that anno2 has a new object, 0605... :

 $ git cat-file -p 0605 | sed 's/@/ /' object a912caa83de69ef8e5e3e06c3d74b6c409068572 type commit tag anno2 tagger Chris Torek <chris.torek gmail.com> 1521060518 -0700 also annotated 

Meanwhile, git for-each-ref describes the maybe-light tag as a tag , not a commit : it just tells us that its immediate target, not following other objects, is a tag, not a commit.

Make another annotated tag, for blob:

 $ git tag -m "annotated blob" annoblob the-file 

Since this is an annotated tag, git for-each-ref says its type is tag (try it!).

Git calls the tag tracking process to its final tag peeling object, and there is a special syntax for it:

 $ git rev-parse annotag annotag^{} annoblob annoblob^{} dc4695ffede0a877fdc61dc06f5ad5c6d5cfc356 a912caa83de69ef8e5e3e06c3d74b6c409068572 398b3b89e0377b8942e2f84c97a24afaad0dccb0 938c7cff87a9b753ae70d91412d3ead5c95ef932 

Note that this is different from the following immediately after the tag, as we can see that we are analyzing anno2 as follows:

 $ git rev-parse anno2^{} a912caa83de69ef8e5e3e06c3d74b6c409068572 

a912... is the commit id, not the second annotated tag. Compare with:

 $ git rev-parse anno2 anno2^{tag} 060527046d210f0219170cdc6354afe4834ddc6d 060527046d210f0219170cdc6354afe4834ddc6d 

The first finds the identifier of the object to which anno2 points; the second checks that it is a database object of type tag . Both of them, of course, are the same ID, and this is really an object of type tag . We can specifically ask about fixing:

 $ git rev-parse anno2^{commit} a912caa83de69ef8e5e3e06c3d74b6c409068572 

but if we do this with the name annoblob , we get an error:

 $ git rev-parse annoblob^{commit} error: annoblob^{commit}: expected commit type, but the object dereferences to blob type 

therefore, the ^{} syntax exists: it means the following tags until you reach a tag, whatever that is.


1 The four-character limit means that if you name the branch cab , you are fine. If you name it face , is that the name of the branch or the original hash identifier? What if it can be several? See the gitrevisions documentation for tips, but the answer is this: it depends on the command. If you specified a link, refs/heads/face or even just heads/face , it no longer resembles a branch name and an abbreviated hash id. Unfortunately, git checkout requires the unvarnished name of face (but always treats it as a branch name if it can).


Summary

A tag name is simply a name in the refs/tags/ namespace. The git tag command can create new tag names. This name must point to some hash identifier; the identifier can be the identifier of any existing object, or you can git tag create a new tag object.

A tag object or an annotated tag object is an object in the repository database. It has a unique hash identifier, just like commit. It has a tag type (vs commit, which has a commit type). Its metadata consists of a target, a tagger name, a tag name, any message you like, and an optional PGP signature.

A tag object's target is any existing object in the repository database. This object must exist when creating the tag object. This prevents the annotated tag from pointing to itself or a tag object that you have not yet created, which prevents cycles in the chart.

Running git tag to create a new tag creates either just a tag name that points to some existing object, or a tag name that points to a new tag object that points to some existing object. An existing object, no matter what it is, continues to exist.

Running git tag -d removes only the tag name. The tag object, if any, remains in the repository. Like commit objects, it will ultimately be collected and disposed of in the garbage if and only if there are no other links that can be used to reach the tag object. (This happens in the future when git gc is executed.)

+2
source

Source: https://habr.com/ru/post/1498136/


All Articles