[PATCH 2/3] fast-export: fix bug with nested tags

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

 



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




[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]

  Powered by Linux