git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] describe: Break annotated tag ties by tagger date

From
Shawn O. Pearce <spearce@spearce.org>
Date
Apr 11, 2010, 01:54 UTC
Message-ID
<20100411015433.GB23075@spearce.org>
In-Reply-To
<20100411002825.GA23075@spearce.org>

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 of 1 second after the UNIX epoch. This will cause us to prefer an annotated tag that has a valid date, or to simply avoid scanning the tag object again if a 3rd tag was found for the same commit.

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>
---
 builtin/describe.c  |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 t/t6120-describe.sh |    8 ++++--
 2 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/builtin/describe.c b/builtin/describe.c
index 71be2a9..cf98664 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -36,6 +36,7 @@ static const char *diff_index_args[] = {
 struct commit_name {
 	struct tag *tag;
 	int prio; /* annotated tag = 2, tag = 1, head = 0 */
+	unsigned long date;
 	unsigned char sha1[20];
 	char path[FLEX_ARRAY]; /* more */
 };
@@ -43,18 +44,74 @@ static const char *prio_names[] = {
 	"head", "lightweight", "annotated",
 };
 
+static unsigned long tag_date(const unsigned char *sha1)
+{
+	enum object_type type;
+	unsigned long size;
+	char *buf;
+	int offset = 0;
+	unsigned long time = 1;
+
+	buf = read_sha1_file(sha1, &type, &size);
+	if (buf && type == OBJ_TAG) {
+		while (offset < size && buf[offset] != '\n') {
+			int new_offset = offset + 1;
+			while (new_offset < size && buf[new_offset++] != '\n')
+				; /* do nothing */
+			if (!prefixcmp(buf + offset, "tagger ")) {
+				char *line = buf + offset + 7;
+				char *date;
+
+				buf[new_offset] = '\0';
+				date = strchr(line, '>');
+				if (date)
+					time = strtoul(date + 1, NULL, 10);
+				break;
+			}
+			offset = new_offset;
+		}
+	} else
+		error("missing tag %s", sha1_to_hex(sha1));
+	free(buf);
+	return time;
+}
+
+static int replace_name(struct commit_name *e,
+			       int prio,
+			       const unsigned char *sha1,
+			       unsigned long *date)
+{
+	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.
+		 */
+		if (!e->date)
+			e->date = tag_date(e->sha1);
+		*date = tag_date(sha1);
+		if (e->date < *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) {
+	unsigned long date = 0;
+	if (replace_name(e, prio, sha1, &date)) {
 		size_t len = strlen(path)+1;
 		free(e);
 		e = xmalloc(sizeof(struct commit_name) + len);
 		e->tag = NULL;
 		e->prio = prio;
+		e->date = date;
 		hashcpy(e->sha1, sha1);
 		memcpy(e->path, path, len);
 		commit->util = e;
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 065dead..876d1ab 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -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
 
@@ -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 &&
@@ -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^
-- 
1.7.1.rc1.232.gc76b8

-- 
Shawn.
Previous: Shawn O. PearceNext: Junio C Hamano
Message 5 of 17 in “git describe bug?”
  1. Dustin SallingsApr 2, 2010
  2. Shawn O. PearceApr 2, 2010
  3. Andreas EricssonApr 6, 2010
  4. Shawn O. PearceApr 11, 2010
  5. describe: Break annotated tag ties by tagger dateShawn O. Pearce, Apr 11, 2010
  6. Junio C HamanoApr 11, 2010
  7. Shawn O. PearceApr 11, 2010
  8. 1/5 tag.c: Correct indentationShawn O. Pearce, Apr 12, 2010
  9. 2/5 tag.h: Remove unused signature fieldShawn O. Pearce, Apr 12, 2010
  10. 3/5 tag.c: Refactor parse_tag_buffer to be saner to programShawn O. Pearce, Apr 12, 2010
  11. 4/5 tag.c: Parse tagger date (if present)Shawn O. Pearce, Apr 12, 2010
  12. 5/5 describe: Break annotated tag ties by tagger dateShawn O. Pearce, Apr 12, 2010
  13. Andreas EricssonApr 13, 2010
  14. Thomas RastApr 13, 2010
  15. Shawn O. PearceApr 13, 2010
  16. Junio C HamanoApr 13, 2010
  17. Shawn O. PearceApr 13, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.