git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git-tag bug? confusing git fast-export with double tag objects

From
MAMatthias Andree <matthias.andree@gmx.de>
Date
May 14, 2009, 09:37 UTC
Message-ID
<op.utwyczlf1e62zd@merlin.emma.line.org>
In-Reply-To
<7v8wl01iev.fsf@alter.siamese.dyndns.org>
Am 14.05.2009, 05:18 Uhr, schrieb Junio C Hamano <gitster@pobox.com>:
Show 23 quoted lines
> "Matthias Andree" <matthias.andree@gmx.de> writes:
>
>> Am 14.05.2009, 02:53 Uhr, schrieb Matthias Andree  
>> <matthias.andree@gmx.de>:
>>
>>> 2. how do I trash the accidentally created 2nd "baz" tag object,
>>> i. e.  remove it from the (packed) object database? Of course, I can
>>> hack some  script (or use a text editor) to grind this
>>> git-fast-export into shape  and re-importing it...
>>
>> OK, that worked: I traced (with git cat-file) the tree through all
>> tagged  tag until the first tagged commit, and hack packed-refs (or
>> refs/tags/foo)  to point to the commit object, and afterwards prune
>> the dangling tag.
>>
>> However, the other questions remain. I'd think git tag should
>> dereference  its 2nd non-option argument to a commit before laying
>> down the tag...
>
> No.  You can tag any object, and a tag is an object.  You can point a
> signed tag with your own signed tag to attest your own belief on that
> other guy's tag, be it "it's genuine", "the tagged commit suits my need",
> etc.
OK, so I can tag/sign any object, fine.
HOWEVER, I see two problems here (yes, they are corner cases):

#1: git tag -f ("replace tag") fails to "replace" a heaviweight tag if I try to replace a tag by itself (or create a cycle by some other means).

The new "foo" is unique in refs (OK), but it's *not unique* in objects (FAIL), as the old "foo" is referenced by the new "foo" and bears the same tag name.

It screws the repo, breaking the uniqueness of tags. Basically, git tag -f is implementing a half-baked, non-working "rebase tag objects" functionality.

#2: related: git tag -d cannot reliably delete tag objects

Same here: if another tag object references the tag object I'm deleting, we only delete the ref, but not the tag object. It doesn't (cannot) become dangling.

Watch:
$ cd $(mktemp -d)
$ git init
Initialized empty Git repository in /tmp/tmp.GBjHED4Xj8/.git/
$ date >a
$ git add a
$ git commit -m "new file a" -a
[master (root-commit) 4481a15] new file a
  1 files changed, 1 insertions(+), 0 deletions(-)
  create mode 100644 a
$ LANG=C git tag foo -m "add tag foo" -s
[GPG passphrase query]
$ LANG=C git tag foo foo -m "add tag foo" -s
fatal: tag 'foo' already exists
-> this is ok, now let's break uniqueness:

$ LANG=C git tag foo foo -m "add tag foo" -s -f [GPG passphrase query] $ git rev-list --objects --all 4481a15d999b1b13066fe932e35ea05b8b1027a6 72f3463f5a8089ac91001d458ceffb6d4e1056ee foo 2e326d8a210536b7cd1f2bc77e3e29d7231f9ec4 foo 995773fc9b649922936e110207e6abb904cc18e8 15a9779d8f787428e57830410c7842e5449dfd33 a $ git show-ref 4481a15d999b1b13066fe932e35ea05b8b1027a6 refs/heads/master 72f3463f5a8089ac91001d458ceffb6d4e1056ee refs/tags/foo $ git cat-file tag 72f346 object 2e326d8a210536b7cd1f2bc77e3e29d7231f9ec4 type tag tag foo tagger Matthias Andree <matthias.andree@gmx.de> 1242289836 +0200

add tag foo -----BEGIN PGP SIGNATURE----- ... $ $ git cat-file tag 2e326d object 4481a15d999b1b13066fe932e35ea05b8b1027a6 type commit tag foo tagger Matthias Andree <matthias.andree@gmx.de> 1242289732 +0200

add tag foo -----BEGIN PGP SIGNATURE----- ...

So what we get is (root/parents first, then children):

objects: 4481a1 (commit) <- 2e326d (tag "foo") <- 72f346 (tag "foo") refs: heads/master tags/foo

Whoops. "foo" is there twice, and it's referenced from a current ref. We have *not* *replaced* it. *If* we did, we should have got:

objects: 4481a1 (commit) <- 72f346 (tag "foo") refs: heads/master tags/foo with a dangling tag 2e326d

> I thought there was a breakage report followed by a fix to the  
> fast-export that mishandled a tag that points at another tag not too  
> long ago.  Do you have 1982467 (builtin-fast-export.c: handle nested  
> tags, 2009-03-23)?

I have that beast (how do I QUICKLY check if that is reachable from refs/master? git log | grep isn't exactly quick), but I think that's unrelated. The real problem is the tag name is no longer unique, and we must prevent that.

Let's screw with the tag objects even more (fresh repo, some "otherfile"):

$ git tag -m "old tag1" -a tag1 $ git tag -m "tag2" -a tag2 tag1 $ git tag -m "new tag1" tag1 tag2 fatal: tag 'tag1' already exists $ git tag -f -m "new tag1" tag1 tag2 $ git rev-list --objects tag1 69bf327c5d172fc8e4f63acf4d2e01c474824ce4 8e7a1997726fc5158954569134d2cafad710f6fe tag1 38aea56fec319d8c259a80157dde2432d2d09b2b tag2 9756f6fa98a5cce2aab1f6a6e7dd4de515626e19 tag1 d758baa57a7ef20d44df0535bef1a91bb3dc4f62 d3d8863b140f43f7c07050b9f2e210d41e73edb1 otherfile $ git show-ref 69bf327c5d172fc8e4f63acf4d2e01c474824ce4 refs/heads/master 8e7a1997726fc5158954569134d2cafad710f6fe refs/tags/tag1 38aea56fec319d8c259a80157dde2432d2d09b2b refs/tags/tag2 $ gitk $ git cat-file tag 8e7a object 38aea56fec319d8c259a80157dde2432d2d09b2b type tag tag tag1 tagger Matthias Andree <matthias.andree@gmx.de> 1242292320 +0200

new tag1 $ git cat-file tag 38ae object 9756f6fa98a5cce2aab1f6a6e7dd4de515626e19 type tag tag tag2 tagger Matthias Andree <matthias.andree@gmx.de> 1242292301 +0200

tag2 $ git cat-file tag 9756 object 69bf327c5d172fc8e4f63acf4d2e01c474824ce4 type commit tag tag1 tagger Matthias Andree <matthias.andree@gmx.de> 1242292293 +0200

old tag1
Hu, there's a nice cycle:
69bf (commit) <- 9756 ('old' tag1) <- 38ae (tag2) <- 8e7a (tag1)
Now, more fun - watch the inconsistency:

$ git tag -d tag1 Deleted tag 'tag1' $ git tag -d tag1 error: tag 'tag1' not found.

Ha! As if... now watch this: $ git rev-list --objects --all | while read a b ; do echo "$a $(git cat-file -t $a) $b" ; done 69bf327c5d172fc8e4f63acf4d2e01c474824ce4 commit 38aea56fec319d8c259a80157dde2432d2d09b2b tag tag2 9756f6fa98a5cce2aab1f6a6e7dd4de515626e19 tag tag1 d758baa57a7ef20d44df0535bef1a91bb3dc4f62 tree d3d8863b140f43f7c07050b9f2e210d41e73edb1 blob otherfile

The tag object "tag1" is still there. WHOOPS!!!

I appreciate that this isn't trivial to solve, but I presume anything that walks the object database and uses tags can fail - including, but not limited to, git fast-export.

Either git tag -f/-d should complain and refuse if it cannot replace/remove the tag because it wouldn't become dangling (other dependencies on it, best to list them), or it would have to recursively trash all its children, too - and perhaps require -f -f be specified for this recursive replacing/removal.

-- 
Matthias Andree
Previous: Junio C HamanoNext: Michael J Gruber
Message 4 of 30 in “git-tag bug? confusing git fast-export with double tag objects”
  1. Matthias AndreeMay 14, 2009
  2. Matthias AndreeMay 14, 2009
  3. Junio C HamanoMay 14, 2009
  4. Matthias AndreeMay 14, 2009
  5. Michael J GruberMay 14, 2009
  6. Alex RiesenMay 14, 2009
  7. Matthias AndreeMay 14, 2009
  8. Alex RiesenMay 14, 2009
  9. Matthias AndreeMay 14, 2009
  10. Sverre RabbelierMay 14, 2009
  11. Matthias AndreeMay 14, 2009
  12. Brandon CaseyMay 14, 2009
  13. Jeff KingMay 14, 2009
  14. Matthias AndreeMay 14, 2009
  15. Jeff KingMay 15, 2009
  16. Matthias AndreeMay 15, 2009
  17. Jakub NarebskiMay 15, 2009
  18. Johannes SixtMay 15, 2009
  19. Alex RiesenMay 15, 2009
  20. Matthias AndreeMay 15, 2009
  21. Andreas EricssonMay 15, 2009
  22. Junio C HamanoMay 15, 2009
  23. Andreas EricssonMay 16, 2009
  24. Jakub NarebskiMay 16, 2009
  25. Andreas EricssonMay 16, 2009
  26. Junio C HamanoMay 16, 2009
  27. Matthias AndreeMay 19, 2009
  28. Jeff KingMay 19, 2009
  29. Jeff KingMay 16, 2009
  30. Daniel ChengMay 15, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.