mirror of
https://github.com/git/git
synced 2024-08-27 03:29:21 +00:00
Merge branch 'sp/maint-describe-tiebreak-with-tagger-date' into maint
* sp/maint-describe-tiebreak-with-tagger-date: describe: Break annotated tag ties by tagger date tag.c: Parse tagger date (if present) tag.c: Refactor parse_tag_buffer to be saner to program tag.h: Remove unused signature field tag.c: Correct indentation
This commit is contained in:
commit
f62e53c897
|
@ -35,7 +35,8 @@ static const char *diff_index_args[] = {
|
||||||
|
|
||||||
struct commit_name {
|
struct commit_name {
|
||||||
struct tag *tag;
|
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];
|
unsigned char sha1[20];
|
||||||
char path[FLEX_ARRAY]; /* more */
|
char path[FLEX_ARRAY]; /* more */
|
||||||
};
|
};
|
||||||
|
@ -43,18 +44,53 @@ static const char *prio_names[] = {
|
||||||
"head", "lightweight", "annotated",
|
"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,
|
static void add_to_known_names(const char *path,
|
||||||
struct commit *commit,
|
struct commit *commit,
|
||||||
int prio,
|
int prio,
|
||||||
const unsigned char *sha1)
|
const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
struct commit_name *e = commit->util;
|
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;
|
size_t len = strlen(path)+1;
|
||||||
free(e);
|
free(e);
|
||||||
e = xmalloc(sizeof(struct commit_name) + len);
|
e = xmalloc(sizeof(struct commit_name) + len);
|
||||||
e->tag = NULL;
|
e->tag = tag;
|
||||||
e->prio = prio;
|
e->prio = prio;
|
||||||
|
e->name_checked = 0;
|
||||||
hashcpy(e->sha1, sha1);
|
hashcpy(e->sha1, sha1);
|
||||||
memcpy(e->path, path, len);
|
memcpy(e->path, path, len);
|
||||||
commit->util = e;
|
commit->util = e;
|
||||||
|
@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)
|
||||||
{
|
{
|
||||||
if (n->prio == 2 && !n->tag) {
|
if (n->prio == 2 && !n->tag) {
|
||||||
n->tag = lookup_tag(n->sha1);
|
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);
|
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))
|
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
|
||||||
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
||||||
|
n->name_checked = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n->tag)
|
if (n->tag)
|
||||||
|
|
|
@ -8,7 +8,7 @@ test_description='test describe
|
||||||
o----o----o----o----o----. /
|
o----o----o----o----o----. /
|
||||||
\ A c /
|
\ A c /
|
||||||
.------------o---o---o
|
.------------o---o---o
|
||||||
D e
|
D,R e
|
||||||
'
|
'
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ test_expect_success setup '
|
||||||
echo D >another && git add another && git commit -m D &&
|
echo D >another && git add another && git commit -m D &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
git tag -a -m D D &&
|
git tag -a -m D D &&
|
||||||
|
test_tick &&
|
||||||
|
git tag -a -m R R &&
|
||||||
|
|
||||||
test_tick &&
|
test_tick &&
|
||||||
echo DD >another && git commit -a -m another &&
|
echo DD >another && git commit -a -m another &&
|
||||||
|
@ -89,10 +91,10 @@ test_expect_success setup '
|
||||||
|
|
||||||
check_describe A-* HEAD
|
check_describe A-* HEAD
|
||||||
check_describe A-* HEAD^
|
check_describe A-* HEAD^
|
||||||
check_describe D-* HEAD^^
|
check_describe R-* HEAD^^
|
||||||
check_describe A-* HEAD^^2
|
check_describe A-* HEAD^^2
|
||||||
check_describe B 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
|
||||||
check_describe c-* --tags HEAD^
|
check_describe c-* --tags HEAD^
|
||||||
|
|
71
tag.c
71
tag.c
|
@ -36,43 +36,50 @@ struct tag *lookup_tag(const unsigned char *sha1)
|
||||||
return (struct tag *) obj;
|
return (struct tag *) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long parse_tag_date(const char *buf, const char *tail)
|
||||||
|
{
|
||||||
|
const char *dateptr;
|
||||||
|
|
||||||
|
while (buf < tail && *buf++ != '>')
|
||||||
|
/* nada */;
|
||||||
|
if (buf >= tail)
|
||||||
|
return 0;
|
||||||
|
dateptr = buf;
|
||||||
|
while (buf < tail && *buf++ != '\n')
|
||||||
|
/* nada */;
|
||||||
|
if (buf >= tail)
|
||||||
|
return 0;
|
||||||
|
/* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
|
||||||
|
return strtoul(dateptr, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
|
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
|
||||||
{
|
{
|
||||||
int typelen, taglen;
|
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *type_line, *tag_line, *sig_line;
|
|
||||||
char type[20];
|
char type[20];
|
||||||
const char *start = data;
|
const char *bufptr = data;
|
||||||
|
const char *tail = bufptr + size;
|
||||||
|
const char *nl;
|
||||||
|
|
||||||
if (item->object.parsed)
|
if (item->object.parsed)
|
||||||
return 0;
|
return 0;
|
||||||
item->object.parsed = 1;
|
item->object.parsed = 1;
|
||||||
|
|
||||||
if (size < 64)
|
if (size < 64)
|
||||||
return -1;
|
return -1;
|
||||||
if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, sha1))
|
if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
|
||||||
return -1;
|
return -1;
|
||||||
|
bufptr += 48; /* "object " + sha1 + "\n" */
|
||||||
|
|
||||||
type_line = (char *) data + 48;
|
if (prefixcmp(bufptr, "type "))
|
||||||
if (memcmp("\ntype ", type_line-1, 6))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
bufptr += 5;
|
||||||
tag_line = memchr(type_line, '\n', size - (type_line - start));
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
||||||
if (!tag_line || memcmp("tag ", ++tag_line, 4))
|
if (!nl || sizeof(type) <= (nl - bufptr))
|
||||||
return -1;
|
return -1;
|
||||||
|
strncpy(type, bufptr, nl - bufptr);
|
||||||
sig_line = memchr(tag_line, '\n', size - (tag_line - start));
|
type[nl - bufptr] = '\0';
|
||||||
if (!sig_line)
|
bufptr = nl + 1;
|
||||||
return -1;
|
|
||||||
sig_line++;
|
|
||||||
|
|
||||||
typelen = tag_line - type_line - strlen("type \n");
|
|
||||||
if (typelen >= 20)
|
|
||||||
return -1;
|
|
||||||
memcpy(type, type_line + 5, typelen);
|
|
||||||
type[typelen] = '\0';
|
|
||||||
taglen = sig_line - tag_line - strlen("tag \n");
|
|
||||||
item->tag = xmemdupz(tag_line + 4, taglen);
|
|
||||||
|
|
||||||
if (!strcmp(type, blob_type)) {
|
if (!strcmp(type, blob_type)) {
|
||||||
item->tagged = &lookup_blob(sha1)->object;
|
item->tagged = &lookup_blob(sha1)->object;
|
||||||
|
@ -87,6 +94,20 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
|
||||||
item->tagged = NULL;
|
item->tagged = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prefixcmp(bufptr, "tag "))
|
||||||
|
return -1;
|
||||||
|
bufptr += 4;
|
||||||
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
||||||
|
if (!nl)
|
||||||
|
return -1;
|
||||||
|
item->tag = xmemdupz(bufptr, nl - bufptr);
|
||||||
|
bufptr = nl + 1;
|
||||||
|
|
||||||
|
if (!prefixcmp(bufptr, "tagger "))
|
||||||
|
item->date = parse_tag_date(bufptr, tail);
|
||||||
|
else
|
||||||
|
item->date = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
tag.h
2
tag.h
|
@ -9,7 +9,7 @@ struct tag {
|
||||||
struct object object;
|
struct object object;
|
||||||
struct object *tagged;
|
struct object *tagged;
|
||||||
char *tag;
|
char *tag;
|
||||||
char *signature; /* not actually implemented */
|
unsigned long date;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct tag *lookup_tag(const unsigned char *sha1);
|
extern struct tag *lookup_tag(const unsigned char *sha1);
|
||||||
|
|
Loading…
Reference in a new issue