@matheusbsbs / matheus-bagliano / commits / 03e8b541b3
Fork 0

describe: Break annotated tag ties by tagger date

If more than one annotated tag points at the same commit, use the tag whose tagger field has a more recent date stamp. This resolves non-deterministic cases where the maintainer has done: $ git tag -a -m "2.1-rc1" v2.1-rc1 deadbeef $ git tag -a -m "2.1" v2.1 deadbeef If the tag is an older-style annotated tag with no tagger date, we assume a date stamp at the UNIX epoch. This will cause us to prefer an annotated tag that has a valid date. We could also try to consider the tag object chain, favoring a tag that "includes" another one: $ git tag -a -m "2.1-rc0" v2.1-rc1 deadbeef $ git tag -a -m "2.1" v2.1 v2.1-rc1 However traversing the tag's object chain looking for inclusion is much more complicated. Its already very likely that even in these cases the v2.1 tag will have a more recent tagger date than v2.1-rc1, so with this change describe should still resolve this by selecting the more recent v2.1. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Apr 12, 2010 at 16:25 UTC 03e8b541b38d95d1cd7b287963c82617a0469f80
2 files changed +50 -7
builtin-describe.c
+45 -4
@@ -35,7 +35,8 @@ static const char *diff_index_args[] = {
35
36 struct commit_name {
37 struct tag *tag;
38 - int prio; /* annotated tag = 2, tag = 1, head = 0 */
38 + unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
39 + unsigned name_checked:1;
40 unsigned char sha1[20];
41 char path[FLEX_ARRAY]; /* more */
42 };
@@ -43,18 +44,53 @@ static const char *prio_names[] = {
44 "head", "lightweight", "annotated",
45 };
46
47 +static int replace_name(struct commit_name *e,
48 + int prio,
49 + const unsigned char *sha1,
50 + struct tag **tag)
51 +{
52 + if (!e || e->prio < prio)
53 + return 1;
54 +
55 + if (e->prio == 2 && prio == 2) {
56 + /* Multiple annotated tags point to the same commit.
57 + * Select one to keep based upon their tagger date.
58 + */
59 + struct tag *t;
60 +
61 + if (!e->tag) {
62 + t = lookup_tag(e->sha1);
63 + if (!t || parse_tag(t))
64 + return 1;
65 + e->tag = t;
66 + }
67 +
68 + t = lookup_tag(sha1);
69 + if (!t || parse_tag(t))
70 + return 0;
71 + *tag = t;
72 +
73 + if (e->tag->date < t->date)
74 + return 1;
75 + }
76 +
77 + return 0;
78 +}
79 +
80 static void add_to_known_names(const char *path,
81 struct commit *commit,
82 int prio,
83 const unsigned char *sha1)
84 {
85 struct commit_name *e = commit->util;
52 - if (!e || e->prio < prio) {
86 + struct tag *tag = NULL;
87 + if (replace_name(e, prio, sha1, &tag)) {
88 size_t len = strlen(path)+1;
89 free(e);
90 e = xmalloc(sizeof(struct commit_name) + len);
56 - e->tag = NULL;
91 + e->tag = tag;
92 e->prio = prio;
93 + e->name_checked = 0;
94 hashcpy(e->sha1, sha1);
95 memcpy(e->path, path, len);
96 commit->util = e;
@@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)
201 {
202 if (n->prio == 2 && !n->tag) {
203 n->tag = lookup_tag(n->sha1);
168 - if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
204 + if (!n->tag || parse_tag(n->tag))
205 die("annotated tag %s not available", n->path);
206 + }
207 + if (n->tag && !n->name_checked) {
208 + if (!n->tag->tag)
209 + die("annotated tag %s has no embedded name", n->path);
210 if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
211 warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
212 + n->name_checked = 1;
213 }
214
215 if (n->tag)
t/t6120-describe.sh
+5 -3
@@ -8,7 +8,7 @@ test_description='test describe
8 o----o----o----o----o----. /
9 \ A c /
10 .------------o---o---o
11 - D e
11 + D,R e
12 '
13 . ./test-lib.sh
14
@@ -68,6 +68,8 @@ test_expect_success setup '
68 echo D >another && git add another && git commit -m D &&
69 test_tick &&
70 git tag -a -m D D &&
71 + test_tick &&
72 + git tag -a -m R R &&
73
74 test_tick &&
75 echo DD >another && git commit -a -m another &&
@@ -89,10 +91,10 @@ test_expect_success setup '
91
92 check_describe A-* HEAD
93 check_describe A-* HEAD^
92 -check_describe D-* HEAD^^
94 +check_describe R-* HEAD^^
95 check_describe A-* HEAD^^2
96 check_describe B HEAD^^2^
95 -check_describe D-* HEAD^^^
97 +check_describe R-* HEAD^^^
98
99 check_describe c-* --tags HEAD
100 check_describe c-* --tags HEAD^