Skip to content

Commit

Permalink
describe: Break annotated tag ties by tagger date
Browse files Browse the repository at this point in the history
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  deadbee
  $ git tag -a -m "2.1"     v2.1      deadbee

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  deadbee
  $ 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 <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
spearce authored and gitster committed Apr 13, 2010
1 parent e451d06 commit 03e8b54
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
49 changes: 45 additions & 4 deletions builtin-describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,62 @@ static const char *diff_index_args[] = {

struct commit_name {
struct tag *tag;
int prio; /* annotated tag = 2, tag = 1, head = 0 */
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
unsigned char sha1[20];
char path[FLEX_ARRAY]; /* more */
};
static const char *prio_names[] = {
"head", "lightweight", "annotated",
};

static int replace_name(struct commit_name *e,
int prio,
const unsigned char *sha1,
struct tag **tag)
{
if (!e || e->prio < prio)
return 1;

if (e->prio == 2 && prio == 2) {
/* Multiple annotated tags point to the same commit.
* Select one to keep based upon their tagger date.
*/
struct tag *t;

if (!e->tag) {
t = lookup_tag(e->sha1);
if (!t || parse_tag(t))
return 1;
e->tag = t;
}

t = lookup_tag(sha1);
if (!t || parse_tag(t))
return 0;
*tag = t;

if (e->tag->date < t->date)
return 1;
}

return 0;
}

static void add_to_known_names(const char *path,
struct commit *commit,
int prio,
const unsigned char *sha1)
{
struct commit_name *e = commit->util;
if (!e || e->prio < prio) {
struct tag *tag = NULL;
if (replace_name(e, prio, sha1, &tag)) {
size_t len = strlen(path)+1;
free(e);
e = xmalloc(sizeof(struct commit_name) + len);
e->tag = NULL;
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
hashcpy(e->sha1, sha1);
memcpy(e->path, path, len);
commit->util = e;
Expand Down Expand Up @@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)
{
if (n->prio == 2 && !n->tag) {
n->tag = lookup_tag(n->sha1);
if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
if (!n->tag || parse_tag(n->tag))
die("annotated tag %s not available", n->path);
}
if (n->tag && !n->name_checked) {
if (!n->tag->tag)
die("annotated tag %s has no embedded name", n->path);
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
n->name_checked = 1;
}

if (n->tag)
Expand Down
8 changes: 5 additions & 3 deletions t/t6120-describe.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test_description='test describe
o----o----o----o----o----. /
\ A c /
.------------o---o---o
D e
D,R e
'
. ./test-lib.sh

Expand Down Expand Up @@ -68,6 +68,8 @@ test_expect_success setup '
echo D >another && git add another && git commit -m D &&
test_tick &&
git tag -a -m D D &&
test_tick &&
git tag -a -m R R &&
test_tick &&
echo DD >another && git commit -a -m another &&
Expand All @@ -89,10 +91,10 @@ test_expect_success setup '

check_describe A-* HEAD
check_describe A-* HEAD^
check_describe D-* HEAD^^
check_describe R-* HEAD^^
check_describe A-* HEAD^^2
check_describe B HEAD^^2^
check_describe D-* HEAD^^^
check_describe R-* HEAD^^^

check_describe c-* --tags HEAD
check_describe c-* --tags HEAD^
Expand Down

0 comments on commit 03e8b54

Please sign in to comment.