From: Luke Shumaker <lukeshu@xxxxxxxxxxx> The t9350-fast-export.sh 'handling nested tags' test takes an annotated tag named 'muss' and creates a second annotated tag named 'nested' that points to 'muss'. As the test observes, fast-export indeed does spit out a stream that creates a tag named 'nested' that points to another tag. However, the test doesn't do a very thorough job of inspecting the resulting tag. It doesn't notice that the output 'nested' isn't quite the same as the input 'nested'. The 'nested' tags are different because the 'muss' tags that they point to are different; fast-export accidentally creates the 'muss' tag object as saying "tag nested" instead of "tag muss". This is because of a quirk in how the fast-export walk sets the refname for objects that aren't directly pointed to by an exported ref. So, fix the bug by getting the tagname from the tag object itself, rather than from the refname. Signed-off-by: Luke Shumaker <lukeshu@xxxxxxxxxxx> --- builtin/fast-export.c | 28 +++++++++++++++++++++++++--- t/t9350-fast-export.sh | 9 ++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/builtin/fast-export.c b/builtin/fast-export.c index e697f87172..2bf83fe52e 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -550,6 +550,21 @@ static const char *anonymize_refname(const char *refname) return anon.buf; } +static const char *anonymize_tagname(size_t tagname_len, const char *tagname) +{ + /* + * Use anonymize_refname internally, so that the anonymization + * is consistent between a tag's refname and its internal + * tagname (if they were consistent to begin with, anyway). + */ + static struct strbuf as_refname = STRBUF_INIT; + + strbuf_reset(&as_refname); + strbuf_addf(&as_refname, "refs/tags/%.*s", (int)tagname_len, tagname); + + return anonymize_refname(as_refname.buf) + strlen("refs/tags/"); +} + /* * We do not even bother to cache commit messages, as they are unlikely * to be repeated verbatim, and it is not that interesting when they are. @@ -775,6 +790,7 @@ static void handle_tag(const char *refname, struct tag *tag) const char *message; size_t message_size = 0; const char *tagname; + size_t tagname_len; const char *tagger, *tagger_end; struct object *tagged; int tagged_mark; @@ -804,6 +820,12 @@ static void handle_tag(const char *refname, struct tag *tag) message_size = strlen(message); } + tagname = memmem(buf, message ? message - buf : size, "\ntag ", 5); + if (!tagname) + die("malformed tag %s", oid_to_hex(&tag->object.oid)); + tagname += 5; + tagname_len = (size_t)(strchrnul(tagname, '\n') - tagname); + tagger = memmem(buf, message ? message - buf : size, "\ntagger ", 8); if (!tagger) { if (fake_missing_tagger) @@ -821,6 +843,8 @@ static void handle_tag(const char *refname, struct tag *tag) if (anonymize) { refname = anonymize_refname(refname); + tagname = anonymize_tagname(tagname_len, tagname); + tagname_len = strlen(tagname); if (message) { static struct hashmap tags; message = anonymize_str(&tags, anonymize_tag, @@ -890,9 +914,7 @@ static void handle_tag(const char *refname, struct tag *tag) printf("reset %s\nfrom %s\n\n", refname, oid_to_hex(&null_oid)); } - tagname = refname; - skip_prefix(tagname, "refs/tags/", &tagname); - printf("tag %s\n", tagname); + printf("tag %.*s\n", (int)tagname_len, tagname); if (mark_tags) { mark_next_object(&tag->object); printf("mark :%"PRIu32"\n", last_idnum); diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 409b48e244..0bcc1bd54e 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -572,10 +572,17 @@ test_expect_success 'handling tags of blobs' ' test_expect_success 'handling nested tags' ' git tag -a -m "This is a nested tag" nested muss && + NESTED=$(git rev-parse --verify nested) && git fast-export --mark-tags nested >output && grep "^from $ZERO_OID$" output && grep "^tag nested$" output >tag_lines && - test_line_count = 2 tag_lines + test_line_count = 1 tag_lines && + rm -rf new && + mkdir new && + git --git-dir=new/.git init && + (cd new && + git fast-import && + test $NESTED = $(git rev-parse --verify refs/tags/nested)) <output ' test_expect_success 'directory becomes symlink' ' -- 2.31.1