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

[PATCH 1/5] pretty describe: add name info to struct commit

From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Date
Nov 4, 2007, 11:48 UTC
Message-ID
<472DB186.9030909@lsrfire.ath.cx>

This patch prepares the lib'ification of git-describe. As a library function, it can't use commit marks or the util field, as they might already be used by the caller.

Convert all usage of commit marks and the util field to use the three new members of struct commit (name, name_flags, name_prio) instead. A new function, clear_commit_name_flags(), should be used to clear them after the work is done.

add_to_known_names() is merged into get_name(); struct commit_name is merged into struct possible_tag; loading the name is done once before describe() is called instead of doing it inside, but protected by a static variable.

The name unconditionally has the prefix "refs/" cut from it, but not more, so a prefix of "tags/" remains for names found under "refs/tags/". This is dealt with when displaying. Together with the change to pass a minimum name "priority" via the cb_data pointer, this cleans get_name() from any use of global variables, making it ready to serve as a library function (or rather its wrapper, the new function load_commit_names()).

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
 builtin-describe.c |  103 ++++++++++++++++++++++------------------------------
 commit.c           |   21 +++++++++++
 commit.h           |    4 ++
 3 files changed, 69 insertions(+), 59 deletions(-)
diff --git a/builtin-describe.c b/builtin-describe.c
index 6eeb9b5..82c25c3 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -20,42 +20,21 @@ static int tags;	/* But allow any tags if --tags is specified */
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
 
-struct commit_name {
-	int prio; /* annotated tag = 2, tag = 1, head = 0 */
-	char path[FLEX_ARRAY]; /* more */
-};
 static const char *prio_names[] = {
 	"head", "lightweight", "annotated",
 };
 
-static void add_to_known_names(const char *path,
-			       struct commit *commit,
-			       int prio)
-{
-	struct commit_name *e = commit->util;
-	if (!e || e->prio < prio) {
-		size_t len = strlen(path)+1;
-		free(e);
-		e = xmalloc(sizeof(struct commit_name) + len);
-		e->prio = prio;
-		memcpy(e->path, path, len);
-		commit->util = e;
-	}
-}
-
 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	struct object *object;
+	int min_prio = *((int *)cb_data);
 	int prio;
 
 	if (!commit)
 		return 0;
 	object = parse_object(sha1);
-	/* If --all, then any refs are used.
-	 * If --tags, then any tags are used.
-	 * Otherwise only annotated tags are used.
-	 */
+
 	if (!prefixcmp(path, "refs/tags/")) {
 		if (object->type == OBJ_TAG)
 			prio = 2;
@@ -64,19 +43,28 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 	}
 	else
 		prio = 0;
+	if (prio < min_prio)
+		return 0;
 
-	if (!all) {
-		if (!prio)
-			return 0;
-		if (!tags && prio < 2)
+	if (commit->name) {
+		if (commit->name_prio >= prio)
 			return 0;
+		free(commit->name);
 	}
-	add_to_known_names(all ? path + 5 : path + 10, commit, prio);
+	commit->name = xstrdup(path + 5);
+	commit->name_prio = prio;
+
 	return 0;
 }
 
+void load_commit_names(int min_prio)
+{
+	for_each_ref(get_name, &min_prio);
+}
+
 struct possible_tag {
-	struct commit_name *name;
+	char *name;
+	int prio; /* annotated tag = 2, tag = 1, head = 0 */
 	int depth;
 	int found_order;
 	unsigned flag_within;
@@ -86,8 +74,8 @@ static int compare_pt(const void *a_, const void *b_)
 {
 	struct possible_tag *a = (struct possible_tag *)a_;
 	struct possible_tag *b = (struct possible_tag *)b_;
-	if (a->name->prio != b->name->prio)
-		return b->name->prio - a->name->prio;
+	if (a->prio != b->prio)
+		return b->prio - a->prio;
 	if (a->depth != b->depth)
 		return a->depth - b->depth;
 	if (a->found_order != b->found_order)
@@ -104,11 +92,11 @@ static unsigned long finish_depth_computation(
 		struct commit *c = pop_commit(list);
 		struct commit_list *parents = c->parents;
 		seen_commits++;
-		if (c->object.flags & best->flag_within) {
+		if (c->name_flags & best->flag_within) {
 			struct commit_list *a = *list;
 			while (a) {
 				struct commit *i = a->item;
-				if (!(i->object.flags & best->flag_within))
+				if (!(i->name_flags & best->flag_within))
 					break;
 				a = a->next;
 			}
@@ -119,9 +107,9 @@ static unsigned long finish_depth_computation(
 		while (parents) {
 			struct commit *p = parents->item;
 			parse_commit(p);
-			if (!(p->object.flags & SEEN))
+			if (!(p->name_flags & SEEN))
 				insert_by_date(p, list);
-			p->object.flags |= c->object.flags;
+			p->name_flags |= c->name_flags;
 			parents = parents->next;
 		}
 	}
@@ -133,8 +121,6 @@ static void describe(const char *arg, int last_one)
 	unsigned char sha1[20];
 	struct commit *cmit, *gave_up_on = NULL;
 	struct commit_list *list;
-	static int initialized = 0;
-	struct commit_name *n;
 	struct possible_tag all_matches[MAX_TAGS];
 	unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
 	unsigned long seen_commits = 0;
@@ -145,14 +131,8 @@ static void describe(const char *arg, int last_one)
 	if (!cmit)
 		die("%s is not a valid '%s' object", arg, commit_type);
 
-	if (!initialized) {
-		initialized = 1;
-		for_each_ref(get_name, NULL);
-	}
-
-	n = cmit->util;
-	if (n) {
-		printf("%s\n", n->path);
+	if (cmit->name) {
+		printf("%s\n", all ? cmit->name : cmit->name + 5);
 		return;
 	}
 
@@ -160,22 +140,22 @@ static void describe(const char *arg, int last_one)
 		fprintf(stderr, "searching to describe %s\n", arg);
 
 	list = NULL;
-	cmit->object.flags = SEEN;
+	cmit->name_flags = SEEN;
 	commit_list_insert(cmit, &list);
 	while (list) {
 		struct commit *c = pop_commit(&list);
 		struct commit_list *parents = c->parents;
 		seen_commits++;
-		n = c->util;
-		if (n) {
+		if (c->name) {
 			if (match_cnt < max_candidates) {
 				struct possible_tag *t = &all_matches[match_cnt++];
-				t->name = n;
+				t->name = all ? c->name : c->name + 5;
+				t->prio = c->name_prio;
 				t->depth = seen_commits - 1;
 				t->flag_within = 1u << match_cnt;
 				t->found_order = match_cnt;
-				c->object.flags |= t->flag_within;
-				if (n->prio == 2)
+				c->name_flags |= t->flag_within;
+				if (c->name_prio == 2)
 					annotated_cnt++;
 			}
 			else {
@@ -185,7 +165,7 @@ static void describe(const char *arg, int last_one)
 		}
 		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
 			struct possible_tag *t = &all_matches[cur_match];
-			if (!(c->object.flags & t->flag_within))
+			if (!(c->name_flags & t->flag_within))
 				t->depth++;
 		}
 		if (annotated_cnt && !list) {
@@ -197,9 +177,9 @@ static void describe(const char *arg, int last_one)
 		while (parents) {
 			struct commit *p = parents->item;
 			parse_commit(p);
-			if (!(p->object.flags & SEEN))
+			if (!(p->name_flags & SEEN))
 				insert_by_date(p, &list);
-			p->object.flags |= c->object.flags;
+			p->name_flags |= c->name_flags;
 			parents = parents->next;
 		}
 	}
@@ -220,8 +200,7 @@ static void describe(const char *arg, int last_one)
 		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
 			struct possible_tag *t = &all_matches[cur_match];
 			fprintf(stderr, " %-11s %8d %s\n",
-				prio_names[t->name->prio],
-				t->depth, t->name->path);
+				prio_names[t->prio], t->depth, t->name);
 		}
 		fprintf(stderr, "traversed %lu commits\n", seen_commits);
 		if (gave_up_on) {
@@ -233,14 +212,14 @@ static void describe(const char *arg, int last_one)
 		}
 	}
 	if (abbrev == 0)
-		printf("%s\n", all_matches[0].name->path );
+		printf("%s\n", all_matches[0].name);
 	else
-		printf("%s-%d-g%s\n", all_matches[0].name->path,
+		printf("%s-%d-g%s\n", all_matches[0].name,
 		       all_matches[0].depth,
 		       find_unique_abbrev(cmit->object.sha1, abbrev));
 
 	if (!last_one)
-		clear_commit_marks(cmit, -1);
+		clear_commit_name_flags(cmit);
 }
 
 int cmd_describe(int argc, const char **argv, const char *prefix)
@@ -275,6 +254,12 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		return cmd_name_rev(3 + argc, args, prefix);
 	}
 
+	/* If --all, then any refs are used.
+	 * If --tags, then any tags are used.
+	 * Otherwise only annotated tags are used.
+	 */
+	load_commit_names(all ? 0 : (tags ? 1 : 2));
+
 	if (argc == 0) {
 		describe("HEAD", 1);
 	} else {
diff --git a/commit.c b/commit.c
index ac24266..24b7268 100644
--- a/commit.c
+++ b/commit.c
@@ -460,6 +460,27 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
 	}
 }
 
+void clear_commit_name_flags(struct commit *commit)
+{
+	while (commit) {
+		struct commit_list *parents;
+
+		if (!commit->name_flags)
+			return;
+
+		commit->name_flags = 0;
+
+		parents = commit->parents;
+		if (!parents)
+			return;
+
+		while ((parents = parents->next))
+			clear_commit_name_flags(parents->item);
+
+		commit = commit->parents->item;
+	}
+}
+
 /*
  * Generic support for pretty-printing the header
  */
diff --git a/commit.h b/commit.h
index b661503..80e94b9 100644
--- a/commit.h
+++ b/commit.h
@@ -18,6 +18,9 @@ struct commit {
 	struct commit_list *parents;
 	struct tree *tree;
 	char *buffer;
+	char *name;
+	unsigned int name_flags;
+	char name_prio;
 };
 
 extern int save_commit_buffer;
@@ -78,6 +81,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
 struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
+void clear_commit_name_flags(struct commit *commit);
 
 /*
  * Performs an in-place topological sort of list supplied.
-- 
1.5.3.5.529.ge3d6d
Next: Alex Riesen
Message 1 of 4 in “pretty describe: add name info to struct commit”
  1. 1/5 pretty describe: add name info to struct commitRené Scharfe, Nov 4, 2007
  2. Alex RiesenNov 4, 2007
  3. Johannes SchindelinNov 4, 2007
  4. René ScharfeNov 4, 2007

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.