{"thread":{"id":"23303","subject":"git describe bug?","startedAt":"2010-04-02T17:20:44Z","lastAt":"2010-04-13T19:46:23Z","messageCount":17,"participants":["Dustin Sallings","Shawn O. Pearce","Andreas Ericsson","Junio C Hamano","Thomas Rast"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"138440","messageId":"0B8BD2B7-E6F9-4EFC-BCD6-2B2E876AD1FC@spy.net","threadId":"23303","inReplyTo":null,"subject":"git describe bug?","fromName":"Dustin Sallings","fromEmail":"dustin@spy.net","sentAt":"2010-04-02T17:20:44Z","receivedAt":"2010-04-02T17:20:44Z","isPatch":false,"sender":{"key":"dustin@spy.net","avatar":"https://gravatar.com/avatar/1750c3935110d421b32d60d412eae0eb49acfcf181605df9adaddb04a9878664?d=mp&s=160"},"body":"\n\tdescribe does not choose the most recent tag when multiple tags point to a single commit (for example, when an RC release becomes a proper release).\n\n\tThere's a bit of conflict in the documentation between the following:\n\n\t\t``tags with newer dates will always be preferred over tags with older dates''\n\n\tand the next sentence:\n\n\t\t``If an exact match is found, its name will be output and searching will stop.''\n\n\tThe code does not allow for multiple exact matches, leading to what I would consider incorrect behavior as shown below:\n\n\ndhcp-103:/tmp/x 1212% git init\nInitialized empty Git repository in /private/tmp/x/.git/\ndhcp-103:/tmp/x 1213% git config user.email me@example.com\ndhcp-103:/tmp/x 1214% git commit --allow-empty -m initial\n[master (root-commit) 7eb97db] initial\ndhcp-103:/tmp/x 1215% git commit --allow-empty -m second\n[master 86544e0] second\ndhcp-103:/tmp/x 1216% git tag -m first 1.0\ndhcp-103:/tmp/x 1217% git describe                      # expect 1.0\n1.0\ndhcp-103:/tmp/x 1218% git tag -m second 2.0\ndhcp-103:/tmp/x 1219% git describe                      # expect 2.0\n1.0\ndhcp-103:/tmp/x 1220% git show-ref \n86544e0414d9d4bc0767eed1ffe36b655638fe81 refs/heads/master\n2594a45768685b7fbf69cf2e2fca087cdf3cbfec refs/tags/1.0\n175a0473faa32cacff0b42f165d39a9547025432 refs/tags/2.0\ndhcp-103:/tmp/x 1221% git cat-file tag refs/tags/1.0\nobject 86544e0414d9d4bc0767eed1ffe36b655638fe81\ntype commit\ntag 1.0\ntagger Dustin Sallings <me@example.com> 1270227996 -0700\n\nfirst\n0.000u 0.001s 0:00.00 0.0%\t0+0k 0+0io 0pf+0w\ndhcp-103:/tmp/x 1222% git cat-file tag refs/tags/2.0\nobject 86544e0414d9d4bc0767eed1ffe36b655638fe81\ntype commit\ntag 2.0\ntagger Dustin Sallings <me@example.com> 1270228008 -0700\n\nsecond\n\n\n-- \nDustin Sallings\n"},{"id":"138444","messageId":"20100402183147.GA20007@spearce.org","threadId":"23303","inReplyTo":"0B8BD2B7-E6F9-4EFC-BCD6-2B2E876AD1FC@spy.net","subject":"Re: git describe bug?","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-02T18:31:47Z","receivedAt":"2010-04-02T18:31:47Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Dustin Sallings <dustin@spy.net> wrote:\n> \n> \tdescribe does not choose the most recent tag when multiple tags point to a single commit (for example, when an RC release becomes a proper release).\n> \n> \tThere's a bit of conflict in the documentation between the following:\n> \n> \t\t``tags with newer dates will always be preferred over tags with older dates''\n> \n> \tand the next sentence:\n> \n> \t\t``If an exact match is found, its name will be output and searching will stop.''\n> \n> \tThe code does not allow for multiple exact matches, leading to what I would consider incorrect behavior as shown below:\n\nYes, I've seen this too.  IIRC we've actually discussed this in\nthe past.  I can't find the thread (my search skills are sub-par\ndespite who I work for...).  But the general idea if I remember\nit right was we wanted to use the older tag, because that tag\ncame first.\n\nSo its probably more a documentation bug than a software bug.\n\n-- \nShawn.\n"},{"id":"138733","messageId":"4BBB0377.8080007@op5.se","threadId":"23303","inReplyTo":"20100402183147.GA20007@spearce.org","subject":"Re: git describe bug?","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2010-04-06T09:48:39Z","receivedAt":"2010-04-06T09:48:39Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"On 04/02/2010 08:31 PM, Shawn O. Pearce wrote:\n> Dustin Sallings<dustin@spy.net>  wrote:\n>>\n>> \tdescribe does not choose the most recent tag when multiple tags point to a single commit (for example, when an RC release becomes a proper release).\n>>\n>> \tThere's a bit of conflict in the documentation between the following:\n>>\n>> \t\t``tags with newer dates will always be preferred over tags with older dates''\n>>\n>> \tand the next sentence:\n>>\n>> \t\t``If an exact match is found, its name will be output and searching will stop.''\n>>\n>> \tThe code does not allow for multiple exact matches, leading to what I would consider incorrect behavior as shown below:\n> \n> Yes, I've seen this too.  IIRC we've actually discussed this in\n> the past.  I can't find the thread (my search skills are sub-par\n> despite who I work for...).  But the general idea if I remember\n> it right was we wanted to use the older tag, because that tag\n> came first.\n> \n\nRight now the behaviour is inconsistent. In the latest git repo\nI tried the following:\n  $ git tag -a v99 -msdf\n  $ git tag -a v100 -m100\n  $ git describe\nv100\n  $ git describe v99\nv100\n  $ git describe v100\nv100\n  $ git show v99\ntag v99\nTagger: Andreas Ericsson <ae@op5.se>\nDate:   Tue Apr 6 11:27:28 2010 +0200\n\nsdf\n\ncommit 8b5fe8c9ec3f961ec9b09844eca6225f06af5b0b\n...\n  $ git show v100\ntag v100\nTagger: Andreas Ericsson <ae@op5.se>\nDate:   Tue Apr 6 11:27:37 2010 +0200\n\n100\n\ncommit 8b5fe8c9ec3f961ec9b09844eca6225f06af5b0b\n...\n\n  $ ls .git/refs/tags/v{100,99}\n.git/refs/tags/v100  .git/refs/tags/v99\n\nSo as you can see, something else is going on. Both tags here are\nstashed as loose objects and both refs are unpacked.\n\nUsing either strverscmp(3) or allowing one to sort by tagging date\nwith the option to use first or latest would be preferrable. I'll\nsee what I can cook up during my lunch-break.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\nConsidering the successes of the wars on alcohol, poverty, drugs and\nterror, I think we should give some serious thought to declaring war\non peace.\n"},{"id":"139219","messageId":"20100411002825.GA23075@spearce.org","threadId":"23303","inReplyTo":"4BBB0377.8080007@op5.se","subject":"Re: git describe bug?","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-11T00:28:25Z","receivedAt":"2010-04-11T00:28:25Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Andreas Ericsson <ae@op5.se> wrote:\n> Right now the behaviour is inconsistent.\n...\n> So as you can see, something else is going on. Both tags here are\n> stashed as loose objects and both refs are unpacked.\n\nIts the order the names were iterated out of the directory by\nreaddir().  Or the order they were sorted by lexographical ordering\nduring for_each_ref().  I can't remember if for_each_ref() sorts\nthe items before processing.\n\nBut either describe uses the first item it found for a given commit\nif they have the same priority.  There's no notion of date being\nfactored into the decision of which tag to keep.\n\nI'll work up a patch right now.\n\n-- \nShawn.\n"},{"id":"139228","messageId":"20100411015433.GB23075@spearce.org","threadId":"23303","inReplyTo":"20100411002825.GA23075@spearce.org","subject":"[PATCH] describe: Break annotated tag ties by tagger date","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-11T01:54:33Z","receivedAt":"2010-04-11T01:54:33Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If more than one annotated tag points at the same commit, use the\ntag whose tagger field has a more recent date stamp.  This resolves\nnon-deterministic cases where the maintainer has done:\n\n  $ git tag -a -m \"2.1-rc1\" v2.1-rc1  deadbeef\n  $ git tag -a -m \"2.1\"     v2.1      deadbeef\n\nIf the tag is an older-style annotated tag with no tagger date,\nwe assume a date stamp of 1 second after the UNIX epoch. This will\ncause us to prefer an annotated tag that has a valid date, or to\nsimply avoid scanning the tag object again if a 3rd tag was found\nfor the same commit.\n\nWe could also try to consider the tag object chain, favoring a tag\nthat \"includes\" another one:\n\n  $ git tag -a -m \"2.1-rc0\" v2.1-rc1  deadbeef\n  $ git tag -a -m \"2.1\"     v2.1      v2.1-rc1\n\nHowever traversing the tag's object chain looking for inclusion\nis much more complicated.  Its already very likely that even in\nthese cases the v2.1 tag will have a more recent tagger date than\nv2.1-rc1, so with this change describe should still resolve this\nby selecting the more recent v2.1.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n builtin/describe.c  |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++-\n t/t6120-describe.sh |    8 ++++--\n 2 files changed, 63 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 71be2a9..cf98664 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -36,6 +36,7 @@ static const char *diff_index_args[] = {\n struct commit_name {\n \tstruct tag *tag;\n \tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n+\tunsigned long date;\n \tunsigned char sha1[20];\n \tchar path[FLEX_ARRAY]; /* more */\n };\n@@ -43,18 +44,74 @@ static const char *prio_names[] = {\n \t\"head\", \"lightweight\", \"annotated\",\n };\n \n+static unsigned long tag_date(const unsigned char *sha1)\n+{\n+\tenum object_type type;\n+\tunsigned long size;\n+\tchar *buf;\n+\tint offset = 0;\n+\tunsigned long time = 1;\n+\n+\tbuf = read_sha1_file(sha1, &type, &size);\n+\tif (buf && type == OBJ_TAG) {\n+\t\twhile (offset < size && buf[offset] != '\\n') {\n+\t\t\tint new_offset = offset + 1;\n+\t\t\twhile (new_offset < size && buf[new_offset++] != '\\n')\n+\t\t\t\t; /* do nothing */\n+\t\t\tif (!prefixcmp(buf + offset, \"tagger \")) {\n+\t\t\t\tchar *line = buf + offset + 7;\n+\t\t\t\tchar *date;\n+\n+\t\t\t\tbuf[new_offset] = '\\0';\n+\t\t\t\tdate = strchr(line, '>');\n+\t\t\t\tif (date)\n+\t\t\t\t\ttime = strtoul(date + 1, NULL, 10);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\toffset = new_offset;\n+\t\t}\n+\t} else\n+\t\terror(\"missing tag %s\", sha1_to_hex(sha1));\n+\tfree(buf);\n+\treturn time;\n+}\n+\n+static int replace_name(struct commit_name *e,\n+\t\t\t       int prio,\n+\t\t\t       const unsigned char *sha1,\n+\t\t\t       unsigned long *date)\n+{\n+\tif (!e || e->prio < prio)\n+\t\treturn 1;\n+\n+\tif (e->prio == 2 && prio == 2) {\n+\t\t/* Multiple annotated tags point to the same commit.\n+\t\t * Select one to keep based upon their tagger date.\n+\t\t */\n+\t\tif (!e->date)\n+\t\t\te->date = tag_date(e->sha1);\n+\t\t*date = tag_date(sha1);\n+\t\tif (e->date < *date)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static void add_to_known_names(const char *path,\n \t\t\t       struct commit *commit,\n \t\t\t       int prio,\n \t\t\t       const unsigned char *sha1)\n {\n \tstruct commit_name *e = commit->util;\n-\tif (!e || e->prio < prio) {\n+\tunsigned long date = 0;\n+\tif (replace_name(e, prio, sha1, &date)) {\n \t\tsize_t len = strlen(path)+1;\n \t\tfree(e);\n \t\te = xmalloc(sizeof(struct commit_name) + len);\n \t\te->tag = NULL;\n \t\te->prio = prio;\n+\t\te->date = date;\n \t\thashcpy(e->sha1, sha1);\n \t\tmemcpy(e->path, path, len);\n \t\tcommit->util = e;\ndiff --git a/t/t6120-describe.sh b/t/t6120-describe.sh\nindex 065dead..876d1ab 100755\n--- a/t/t6120-describe.sh\n+++ b/t/t6120-describe.sh\n@@ -8,7 +8,7 @@ test_description='test describe\n  o----o----o----o----o----.    /\n        \\        A    c        /\n         .------------o---o---o\n-                     D   e\n+                   D,R   e\n '\n . ./test-lib.sh\n \n@@ -68,6 +68,8 @@ test_expect_success setup '\n \techo D >another && git add another && git commit -m D &&\n \ttest_tick &&\n \tgit tag -a -m D D &&\n+\ttest_tick &&\n+\tgit tag -a -m R R &&\n \n \ttest_tick &&\n \techo DD >another && git commit -a -m another &&\n@@ -89,10 +91,10 @@ test_expect_success setup '\n \n check_describe A-* HEAD\n check_describe A-* HEAD^\n-check_describe D-* HEAD^^\n+check_describe R-* HEAD^^\n check_describe A-* HEAD^^2\n check_describe B HEAD^^2^\n-check_describe D-* HEAD^^^\n+check_describe R-* HEAD^^^\n \n check_describe c-* --tags HEAD\n check_describe c-* --tags HEAD^\n-- \n1.7.1.rc1.232.gc76b8\n\n-- \nShawn.\n"},{"id":"139230","messageId":"7vwrwera05.fsf@alter.siamese.dyndns.org","threadId":"23303","inReplyTo":"20100411015433.GB23075@spearce.org","subject":"Re: [PATCH] describe: Break annotated tag ties by tagger date","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-04-11T02:36:10Z","receivedAt":"2010-04-11T02:36:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> If more than one annotated tag points at the same commit, use the\n> tag whose tagger field has a more recent date stamp.  This resolves\n> non-deterministic cases where the maintainer has done:\n\nI think it is a good idea to introduce this tiebreaker to give the listing\nsome degree of stability.  And I also notice that you prepared a patch\nthat can easily apply to an older codebase like 1.6.6 maintenance track.\n\nI have anything against this as an incremental and low impact improvement,\nbut at the same time I think we might want to consider adding the tagger\ndate to \"struct tag\".\n"},{"id":"139231","messageId":"20100411024008.GC23075@spearce.org","threadId":"23303","inReplyTo":"7vwrwera05.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] describe: Break annotated tag ties by tagger date","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-11T02:40:08Z","receivedAt":"2010-04-11T02:40:08Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> \"Shawn O. Pearce\" <spearce@spearce.org> writes:\n> \n> > If more than one annotated tag points at the same commit, use the\n> > tag whose tagger field has a more recent date stamp.  This resolves\n> > non-deterministic cases where the maintainer has done:\n> \n> I think it is a good idea to introduce this tiebreaker to give the listing\n> some degree of stability.  And I also notice that you prepared a patch\n> that can easily apply to an older codebase like 1.6.6 maintenance track.\n> \n> I have anything against this as an incremental and low impact improvement,\n> but at the same time I think we might want to consider adding the tagger\n> date to \"struct tag\".\n\nYea, I thought about that.  It would have simplified the code\nin describe.  But I was also trying to avoid a larger impact.  :-)\n\nI'm more than happy to respin with a new date field in struct tag.\nI just won't be able to get to it before Monday.\n\n-- \nShawn.\n"},{"id":"139376","messageId":"1271114729-18166-1-git-send-email-spearce@spearce.org","threadId":"23303","inReplyTo":"20100411024008.GC23075@spearce.org","subject":"[PATCH v2 1/5] tag.c: Correct indentation","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-12T23:25:25Z","receivedAt":"2010-04-12T23:25:25Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"These lines were incorrectly indented with spaces, violating our\ncoding style.  Its annoying to read with 4 position tab stops, so\nfix the indentation to be correct.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n Respin of the stable describe stuff, this time pushing the date\n parsing into tag.c and the struct tag member.\n\n tag.c |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/tag.c b/tag.c\nindex 4470d2b..52d71bb 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -44,9 +44,9 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n \tchar type[20];\n \tconst char *start = data;\n \n-        if (item->object.parsed)\n-                return 0;\n-        item->object.parsed = 1;\n+\tif (item->object.parsed)\n+\t\treturn 0;\n+\titem->object.parsed = 1;\n \n \tif (size < 64)\n \t\treturn -1;\n-- \n1.7.1.rc1.246.g978a8\n"},{"id":"139378","messageId":"1271114729-18166-2-git-send-email-spearce@spearce.org","threadId":"23303","inReplyTo":"20100411024008.GC23075@spearce.org","subject":"[PATCH v2 2/5] tag.h: Remove unused signature field","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-12T23:25:26Z","receivedAt":"2010-04-12T23:25:26Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Its documented as unused.  So lets just drop it from the structure\nsince we haven't ever used it.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n tag.h |    1 -\n 1 files changed, 0 insertions(+), 1 deletions(-)\n\ndiff --git a/tag.h b/tag.h\nindex 7a0cb00..c437890 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,6 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tchar *signature; /* not actually implemented */\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\n-- \n1.7.1.rc1.246.g978a8\n"},{"id":"139380","messageId":"1271114729-18166-3-git-send-email-spearce@spearce.org","threadId":"23303","inReplyTo":"20100411024008.GC23075@spearce.org","subject":"[PATCH v2 3/5] tag.c: Refactor parse_tag_buffer to be saner to program","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-12T23:25:27Z","receivedAt":"2010-04-12T23:25:27Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This code was horribly ugly to follow.  The structure of the headers\nin an annotated tag object must follow a prescribed order, and most\nof these are required.  Simplify the entire parsing logic by going\nthrough the headers in the order they are supposed to appear in,\nacting on each header as its identified in the buffer.\n\nThis change has the same behavior as the older version, its just\neasier to read and maintain.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n tag.c |   43 +++++++++++++++++++++----------------------\n 1 files changed, 21 insertions(+), 22 deletions(-)\n\ndiff --git a/tag.c b/tag.c\nindex 52d71bb..ceb8655 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -38,11 +38,11 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \n int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n {\n-\tint typelen, taglen;\n \tunsigned char sha1[20];\n-\tconst char *type_line, *tag_line, *sig_line;\n \tchar type[20];\n-\tconst char *start = data;\n+\tconst char *bufptr = data;\n+\tconst char *tail = bufptr + size;\n+\tconst char *nl;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -50,29 +50,19 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n \n \tif (size < 64)\n \t\treturn -1;\n-\tif (memcmp(\"object \", data, 7) || get_sha1_hex((char *) data + 7, sha1))\n+\tif (memcmp(\"object \", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\\n')\n \t\treturn -1;\n+\tbufptr += 48; /* \"object \" + sha1 + \"\\n\" */\n \n-\ttype_line = (char *) data + 48;\n-\tif (memcmp(\"\\ntype \", type_line-1, 6))\n+\tif (prefixcmp(bufptr, \"type \"))\n \t\treturn -1;\n-\n-\ttag_line = memchr(type_line, '\\n', size - (type_line - start));\n-\tif (!tag_line || memcmp(\"tag \", ++tag_line, 4))\n-\t\treturn -1;\n-\n-\tsig_line = memchr(tag_line, '\\n', size - (tag_line - start));\n-\tif (!sig_line)\n-\t\treturn -1;\n-\tsig_line++;\n-\n-\ttypelen = tag_line - type_line - strlen(\"type \\n\");\n-\tif (typelen >= 20)\n+\tbufptr += 5;\n+\tnl = memchr(bufptr, '\\n', tail - bufptr);\n+\tif (!nl || sizeof(type) <= (nl - bufptr))\n \t\treturn -1;\n-\tmemcpy(type, type_line + 5, typelen);\n-\ttype[typelen] = '\\0';\n-\ttaglen = sig_line - tag_line - strlen(\"tag \\n\");\n-\titem->tag = xmemdupz(tag_line + 4, taglen);\n+\tstrncpy(type, bufptr, nl - bufptr);\n+\ttype[nl - bufptr] = '\\0';\n+\tbufptr = nl + 1;\n \n \tif (!strcmp(type, blob_type)) {\n \t\titem->tagged = &lookup_blob(sha1)->object;\n@@ -87,6 +77,15 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n \t\titem->tagged = NULL;\n \t}\n \n+\tif (prefixcmp(bufptr, \"tag \"))\n+\t\treturn -1;\n+\tbufptr += 4;\n+\tnl = memchr(bufptr, '\\n', tail - bufptr);\n+\tif (!nl)\n+\t\treturn -1;\n+\titem->tag = xmemdupz(bufptr, nl - bufptr);\n+\tbufptr = nl + 1;\n+\n \treturn 0;\n }\n \n-- \n1.7.1.rc1.246.g978a8\n"},{"id":"139377","messageId":"1271114729-18166-4-git-send-email-spearce@spearce.org","threadId":"23303","inReplyTo":"20100411024008.GC23075@spearce.org","subject":"[PATCH v2 4/5] tag.c: Parse tagger date (if present)","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-12T23:25:28Z","receivedAt":"2010-04-12T23:25:28Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Just like with committer dates, we parse the tagger date into the\nstruct tag so its available for further downstream processing.\nHowever since the tagger header was not introduced until Git 0.99.1\nwe must consider it optional.  For tags missing this header we use\nthe default date of 0.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n tag.c |   22 ++++++++++++++++++++++\n tag.h |    1 +\n 2 files changed, 23 insertions(+), 0 deletions(-)\n\ndiff --git a/tag.c b/tag.c\nindex ceb8655..85607c2 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -36,6 +36,23 @@ struct tag *lookup_tag(const unsigned char *sha1)\n         return (struct tag *) obj;\n }\n \n+static unsigned long parse_tag_date(const char *buf, const char *tail)\n+{\n+\tconst char *dateptr;\n+\n+\twhile (buf < tail && *buf++ != '>')\n+\t\t/* nada */;\n+\tif (buf >= tail)\n+\t\treturn 0;\n+\tdateptr = buf;\n+\twhile (buf < tail && *buf++ != '\\n')\n+\t\t/* nada */;\n+\tif (buf >= tail)\n+\t\treturn 0;\n+\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n+\treturn strtoul(dateptr, NULL, 10);\n+}\n+\n int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n {\n \tunsigned char sha1[20];\n@@ -86,6 +103,11 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)\n \titem->tag = xmemdupz(bufptr, nl - bufptr);\n \tbufptr = nl + 1;\n \n+\tif (!prefixcmp(bufptr, \"tagger \"))\n+\t\titem->date = parse_tag_date(bufptr, tail);\n+\telse\n+\t\titem->date = 0;\n+\n \treturn 0;\n }\n \ndiff --git a/tag.h b/tag.h\nindex c437890..4766272 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,6 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n+\tunsigned long date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\n-- \n1.7.1.rc1.246.g978a8\n"},{"id":"139379","messageId":"1271114729-18166-5-git-send-email-spearce@spearce.org","threadId":"23303","inReplyTo":"20100411024008.GC23075@spearce.org","subject":"[PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-12T23:25:29Z","receivedAt":"2010-04-12T23:25:29Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If more than one annotated tag points at the same commit, use the\ntag whose tagger field has a more recent date stamp.  This resolves\nnon-deterministic cases where the maintainer has done:\n\n  $ git tag -a -m \"2.1-rc1\" v2.1-rc1  deadbeef\n  $ git tag -a -m \"2.1\"     v2.1      deadbeef\n\nIf the tag is an older-style annotated tag with no tagger date,\nwe assume a date stamp of 1 second after the UNIX epoch. This will\ncause us to prefer an annotated tag that has a valid date, or to\nsimply avoid scanning the tag object again if a 3rd tag was found\nfor the same commit.\n\nWe could also try to consider the tag object chain, favoring a tag\nthat \"includes\" another one:\n\n  $ git tag -a -m \"2.1-rc0\" v2.1-rc1  deadbeef\n  $ git tag -a -m \"2.1\"     v2.1      v2.1-rc1\n\nHowever traversing the tag's object chain looking for inclusion\nis much more complicated.  Its already very likely that even in\nthese cases the v2.1 tag will have a more recent tagger date than\nv2.1-rc1, so with this change describe should still resolve this\nby selecting the more recent v2.1.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n builtin/describe.c  |   49 +++++++++++++++++++++++++++++++++++++++++++++----\n t/t6120-describe.sh |    8 +++++---\n 2 files changed, 50 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 71be2a9..43caff2 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -35,7 +35,8 @@ static const char *diff_index_args[] = {\n \n struct commit_name {\n \tstruct tag *tag;\n-\tint prio; /* annotated tag = 2, tag = 1, head = 0 */\n+\tunsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */\n+\tunsigned name_checked:1;\n \tunsigned char sha1[20];\n \tchar path[FLEX_ARRAY]; /* more */\n };\n@@ -43,18 +44,53 @@ static const char *prio_names[] = {\n \t\"head\", \"lightweight\", \"annotated\",\n };\n \n+static int replace_name(struct commit_name *e,\n+\t\t\t       int prio,\n+\t\t\t       const unsigned char *sha1,\n+\t\t\t       struct tag **tag)\n+{\n+\tif (!e || e->prio < prio)\n+\t\treturn 1;\n+\n+\tif (e->prio == 2 && prio == 2) {\n+\t\t/* Multiple annotated tags point to the same commit.\n+\t\t * Select one to keep based upon their tagger date.\n+\t\t */\n+\t\tstruct tag *t;\n+\n+\t\tif (!e->tag) {\n+\t\t\tt = lookup_tag(e->sha1);\n+\t\t\tif (!t || parse_tag(t))\n+\t\t\t\treturn 1;\n+\t\t\te->tag = t;\n+\t\t}\n+\n+\t\tt = lookup_tag(sha1);\n+\t\tif (!t || parse_tag(t))\n+\t\t\treturn 0;\n+\t\t*tag = t;\n+\n+\t\tif (e->tag->date < t->date)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static void add_to_known_names(const char *path,\n \t\t\t       struct commit *commit,\n \t\t\t       int prio,\n \t\t\t       const unsigned char *sha1)\n {\n \tstruct commit_name *e = commit->util;\n-\tif (!e || e->prio < prio) {\n+\tstruct tag *tag = NULL;\n+\tif (replace_name(e, prio, sha1, &tag)) {\n \t\tsize_t len = strlen(path)+1;\n \t\tfree(e);\n \t\te = xmalloc(sizeof(struct commit_name) + len);\n-\t\te->tag = NULL;\n+\t\te->tag = tag;\n \t\te->prio = prio;\n+\t\te->name_checked = 0;\n \t\thashcpy(e->sha1, sha1);\n \t\tmemcpy(e->path, path, len);\n \t\tcommit->util = e;\n@@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)\n {\n \tif (n->prio == 2 && !n->tag) {\n \t\tn->tag = lookup_tag(n->sha1);\n-\t\tif (!n->tag || parse_tag(n->tag) || !n->tag->tag)\n+\t\tif (!n->tag || parse_tag(n->tag))\n \t\t\tdie(\"annotated tag %s not available\", n->path);\n+\t}\n+\tif (n->tag && !n->name_checked) {\n+\t\tif (!n->tag->tag)\n+\t\t\tdie(\"annotated tag %s has no embedded name\", n->path);\n \t\tif (strcmp(n->tag->tag, all ? n->path + 5 : n->path))\n \t\t\twarning(\"tag '%s' is really '%s' here\", n->tag->tag, n->path);\n+\t\tn->name_checked = 1;\n \t}\n \n \tif (n->tag)\ndiff --git a/t/t6120-describe.sh b/t/t6120-describe.sh\nindex 065dead..876d1ab 100755\n--- a/t/t6120-describe.sh\n+++ b/t/t6120-describe.sh\n@@ -8,7 +8,7 @@ test_description='test describe\n  o----o----o----o----o----.    /\n        \\        A    c        /\n         .------------o---o---o\n-                     D   e\n+                   D,R   e\n '\n . ./test-lib.sh\n \n@@ -68,6 +68,8 @@ test_expect_success setup '\n \techo D >another && git add another && git commit -m D &&\n \ttest_tick &&\n \tgit tag -a -m D D &&\n+\ttest_tick &&\n+\tgit tag -a -m R R &&\n \n \ttest_tick &&\n \techo DD >another && git commit -a -m another &&\n@@ -89,10 +91,10 @@ test_expect_success setup '\n \n check_describe A-* HEAD\n check_describe A-* HEAD^\n-check_describe D-* HEAD^^\n+check_describe R-* HEAD^^\n check_describe A-* HEAD^^2\n check_describe B HEAD^^2^\n-check_describe D-* HEAD^^^\n+check_describe R-* HEAD^^^\n \n check_describe c-* --tags HEAD\n check_describe c-* --tags HEAD^\n-- \n1.7.1.rc1.246.g978a8\n"},{"id":"139403","messageId":"4BC43902.2040903@op5.se","threadId":"23303","inReplyTo":"1271114729-18166-5-git-send-email-spearce@spearce.org","subject":"Re: [PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2010-04-13T09:27:30Z","receivedAt":"2010-04-13T09:27:30Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"On 04/13/2010 01:25 AM, Shawn O. Pearce wrote:\n> If more than one annotated tag points at the same commit, use the\n> tag whose tagger field has a more recent date stamp.  This resolves\n> non-deterministic cases where the maintainer has done:\n> \n>    $ git tag -a -m \"2.1-rc1\" v2.1-rc1  deadbeef\n>    $ git tag -a -m \"2.1\"     v2.1      deadbeef\n> \n\nWe use this patch-series in our buildsystem, where we just now\ntagged about 14 projects as stable (on top of an earlier beta tag).\nEverything's working just fine, so...\n\nTested-By: Andreas Ericsson <ae@op5.se>\n\nThanks a lot, Shawn.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\nConsidering the successes of the wars on alcohol, poverty, drugs and\nterror, I think we should give some serious thought to declaring war\non peace.\n"},{"id":"139405","messageId":"201004131132.30186.trast@student.ethz.ch","threadId":"23303","inReplyTo":"1271114729-18166-5-git-send-email-spearce@spearce.org","subject":"Re: [PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-04-13T09:32:29Z","receivedAt":"2010-04-13T09:32:29Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Shawn O. Pearce wrote:\n> If the tag is an older-style annotated tag with no tagger date,\n> we assume a date stamp of 1 second after the UNIX epoch.\n\nThis patch doesn't seem to actually set this, but as a minor nit: the\n'1 second' contradicts the 0 mentioned in the last patch.\n\n(The effect is the same for all practical purposes.)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"139421","messageId":"20100413140830.GA12635@spearce.org","threadId":"23303","inReplyTo":"201004131132.30186.trast@student.ethz.ch","subject":"Re: [PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-13T14:08:30Z","receivedAt":"2010-04-13T14:08:30Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> wrote:\n> Shawn O. Pearce wrote:\n> > If the tag is an older-style annotated tag with no tagger date,\n> > we assume a date stamp of 1 second after the UNIX epoch.\n> \n> This patch doesn't seem to actually set this, but as a minor nit: the\n> '1 second' contradicts the 0 mentioned in the last patch.\n> \n> (The effect is the same for all practical purposes.)\n\nWhoops.  Old commit message from v1.  I skim read it knowing I\nneeded to adjust something in the message before reusing it, but\ndidn't see anything, so sent it as-is.\n\nJunio, it might make sense to drop the part Thomas quoted above\nbefore you apply this.\n\n-- \nShawn.\n"},{"id":"139429","messageId":"7vbpdnupbm.fsf@alter.siamese.dyndns.org","threadId":"23303","inReplyTo":"20100413140830.GA12635@spearce.org","subject":"Re: [PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-04-13T19:26:05Z","receivedAt":"2010-04-13T19:26:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> Thomas Rast <trast@student.ethz.ch> wrote:\n>> Shawn O. Pearce wrote:\n>> > If the tag is an older-style annotated tag with no tagger date,\n>> > we assume a date stamp of 1 second after the UNIX epoch.\n>> \n>> This patch doesn't seem to actually set this, but as a minor nit: the\n>> '1 second' contradicts the 0 mentioned in the last patch.\n>> \n>> (The effect is the same for all practical purposes.)\n>\n> Whoops.  Old commit message from v1.  I skim read it knowing I\n> needed to adjust something in the message before reusing it, but\n> didn't see anything, so sent it as-is.\n>\n> Junio, it might make sense to drop the part Thomas quoted above\n> before you apply this.\n\nSurely I can, but I am curious as to the motivation behind '1 second' in\nthe original patch.  If you wanted to give these '1 second' ones slight\npreference over the ones with 'date stamp at the UNIX epoch', that logic\nis not there anymore in the re-rolled series, no?\n"},{"id":"139430","messageId":"20100413194623.GA17484@spearce.org","threadId":"23303","inReplyTo":"7vbpdnupbm.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 5/5] describe: Break annotated tag ties by tagger date","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2010-04-13T19:46:23Z","receivedAt":"2010-04-13T19:46:23Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> \"Shawn O. Pearce\" <spearce@spearce.org> writes:\n> \n> > Thomas Rast <trast@student.ethz.ch> wrote:\n> >> Shawn O. Pearce wrote:\n> >> > If the tag is an older-style annotated tag with no tagger date,\n> >> > we assume a date stamp of 1 second after the UNIX epoch.\n> >> \n> >> This patch doesn't seem to actually set this, but as a minor nit: the\n> >> '1 second' contradicts the 0 mentioned in the last patch.\n> \n> Surely I can, but I am curious as to the motivation behind '1 second' in\n> the original patch.  If you wanted to give these '1 second' ones slight\n> preference over the ones with 'date stamp at the UNIX epoch', that logic\n> is not there anymore in the re-rolled series, no?\n\nThe 1-second in the original patch had nothing to do about giving\none tag an edge over another tag.\n\nThe meaning of date in the original patch was:\n\n  date = 0: we haven't yet looked up the date\n  date = 1: we looked it up, but there is no tagger present\n  date > 0: \"valid\" date, we can sort with it\n\nSo date = 1 was just about getting ourselves out of the !date case so\nthat we didn't keep parsing a tag which has no tagger field present.\n\nIn the new version this is handled by the standard parsed field\nof struct object.  So I didn't need to overload the meaning of the\ndate field anymore.\n\nMake sense?\n\n-- \nShawn.\n"}]}