Commit 16541b864d960c6a600938d82c7472f5a188206e

Carlos Martín Nieto 2016-04-25T12:16:05

tag: ignore extra header fields While no extra header fields are defined for tags, git accepts them by ignoring them and continuing the search for the message. There are a few tags like this in the wild which git parses just fine, so we should do the same.

diff --git a/src/tag.c b/src/tag.c
index c4bce1f..fe840fe 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -137,8 +137,14 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
 
 	tag->message = NULL;
 	if (buffer < buffer_end) {
-		if( *buffer != '\n' )
-			return tag_error("No new line before message");
+		/* If we're not at the end of the header, search for it */
+		if( *buffer != '\n' ) {
+			search = strstr(buffer, "\n\n");
+			if (search)
+				buffer = search + 1;
+			else
+				return tag_error("tag contains no message");
+		}
 
 		text_len = buffer_end - ++buffer;
 
diff --git a/tests/object/tag/read.c b/tests/object/tag/read.c
index c9787a4..8f28afd 100644
--- a/tests/object/tag/read.c
+++ b/tests/object/tag/read.c
@@ -140,3 +140,40 @@ void test_object_tag_read__without_tagger_nor_message(void)
 	git_tag_free(tag);
 	git_repository_free(repo);
 }
+
+static const char *silly_tag = "object c054ccaefbf2da31c3b19178f9e3ef20a3867924\n\
+type commit\n\
+tag v1_0_1\n\
+tagger Jamis Buck <jamis@37signals.com> 1107717917\n\
+diff --git a/lib/sqlite3/version.rb b/lib/sqlite3/version.rb\n\
+index 0b3bf69..4ee8fc2 100644\n\
+--- a/lib/sqlite3/version.rb\n\
++++ b/lib/sqlite3/version.rb\n\
+@@ -36,7 +36,7 @@ module SQLite3\n\
+ \n\
+     MAJOR = 1\n\
+     MINOR = 0\n\
+-    TINY  = 0\n\
++    TINY  = 1\n\
+ \n\
+     STRING = [ MAJOR, MINOR, TINY ].join( \".\" )\n\
+ \n\
+ -0600\n\
+\n\
+v1_0_1 release\n";
+
+void test_object_tag_read__extra_header_fields(void)
+{
+	git_tag *tag;
+	git_odb *odb;
+	git_oid id;
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, g_repo));
+
+	cl_git_pass(git_odb_write(&id, odb, silly_tag, strlen(silly_tag), GIT_OBJ_TAG));
+	cl_git_pass(git_tag_lookup(&tag, g_repo, &id));
+
+	cl_assert_equal_s("v1_0_1 release\n", git_tag_message(tag));
+
+	git_tag_free(tag);
+}