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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 14.05.2009, 05:18 Uhr, schrieb Junio C Hamano <gitster@xxxxxxxxx>:

"Matthias Andree" <matthias.andree@xxxxxx> writes:

Am 14.05.2009, 02:53 Uhr, schrieb Matthias Andree <matthias.andree@xxxxxx>:

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@xxxxxx> 1242289836 +0200

add tag foo
-----BEGIN PGP SIGNATURE-----
...
$
$ git cat-file tag 2e326d
object 4481a15d999b1b13066fe932e35ea05b8b1027a6
type commit
tag foo
tagger Matthias Andree <matthias.andree@xxxxxx> 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@xxxxxx> 1242292320 +0200

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

tag2
$ git cat-file tag 9756
object 69bf327c5d172fc8e4f63acf4d2e01c474824ce4
type commit
tag tag1
tagger Matthias Andree <matthias.andree@xxxxxx> 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
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]