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

Re: [PATCH] describe: Don’t look up commits with --exact-match

From
Anders Kaseorg <andersk@ksplice.com>
Date
Dec 6, 2010, 17:28 UTC
Message-ID
<alpine.DEB.2.02.1012061159500.23348@dr-wily.mit.edu>
In-Reply-To
<20101206073214.GA3745@burratino>
On Mon, 6 Dec 2010, Jonathan Nieder wrote:
Show 5 quoted lines
> Depends on what "Don't lookup commits" means, I suppose.  I
> think the difference between _ref and _rawref is
> […]
> so if I understand correctly, for_each_ref would still allow one to
> get away without unpacking the objects.  Is that correct?

Yeah. Okay, I see that “lookup” implies unpacking, as opposed to “find”, which doesn’t. The important part is to avoid the find, of course, because the I/O is expensive.

Anyway, here’s a series with that change split out.
Anders
-- 8< --
From 2ad1e58b8f6e9c117c77748b6e8b85227d9d5412 Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@ksplice.com>
Subject: [PATCH 1/2] describe: Use for_each_rawref

Don’t waste time checking for dangling refs; they wouldn’t affect the output of ‘git describe’ anyway. Although this doesn’t gain much performance by itself, it does in conjunction with the next commit.

Signed-off-by: Anders Kaseorg <andersk@ksplice.com>
---
 builtin/describe.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin/describe.c b/builtin/describe.c
index 43caff2..700f740 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -418,7 +418,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		return cmd_name_rev(i + argc, args, prefix);
 	}
 
-	for_each_ref(get_name, NULL);
+	for_each_rawref(get_name, NULL);
 	if (!found_names && !always)
 		die("No names found, cannot describe anything.");
 
-- 
1.7.3.3


From ce8a2ab9cf80247c2834d21f36f63cedb794e62f Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@ksplice.com>
Subject: describe: Don’t look up commits with --exact-match

This makes ‘git describe --exact-match HEAD’ about 15 times faster on
a cold cache (2.3s instead of 35s) in a linux-2.6 repository with many
packed tags.  That’s a huge win for the interactivity of the __git_ps1
shell prompt helper.

Signed-off-by: Anders Kaseorg <andersk@ksplice.com>
---
 builtin/describe.c |   62 ++++++++++++++++++++++++++-------------------------
 1 files changed, 32 insertions(+), 30 deletions(-)

diff --git a/builtin/describe.c b/builtin/describe.c
index 700f740..0cddef1 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -22,7 +22,7 @@ static int tags;	/* Allow lightweight tags */
 static int longformat;
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
-static int found_names;
+static struct commit_name *names;
 static const char *pattern;
 static int always;
 static const char *dirty;
@@ -34,6 +34,8 @@ static const char *diff_index_args[] = {
 
 
 struct commit_name {
+	struct commit_name *next;
+	unsigned char peeled[20];
 	struct tag *tag;
 	unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
 	unsigned name_checked:1;
@@ -78,31 +80,26 @@ static int replace_name(struct commit_name *e,
 }
 
 static void add_to_known_names(const char *path,
-			       struct commit *commit,
+			       const unsigned char *peeled,
 			       int prio,
 			       const unsigned char *sha1)
 {
-	struct commit_name *e = commit->util;
 	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 = tag;
-		e->prio = prio;
-		e->name_checked = 0;
-		hashcpy(e->sha1, sha1);
-		memcpy(e->path, path, len);
-		commit->util = e;
-	}
-	found_names = 1;
+	size_t len = strlen(path)+1;
+	struct commit_name *e = xmalloc(sizeof(struct commit_name) + len);
+	hashcpy(e->peeled, peeled);
+	e->tag = tag;
+	e->prio = prio;
+	e->name_checked = 0;
+	hashcpy(e->sha1, sha1);
+	memcpy(e->path, path, len);
+	e->next = names;
+	names = e;
 }
 
 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	int might_be_tag = !prefixcmp(path, "refs/tags/");
-	struct commit *commit;
-	struct object *object;
 	unsigned char peeled[20];
 	int is_tag, prio;
 
@@ -110,16 +107,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 		return 0;
 
 	if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
-		commit = lookup_commit_reference_gently(peeled, 1);
-		if (!commit)
-			return 0;
-		is_tag = !!hashcmp(sha1, commit->object.sha1);
+		is_tag = !!hashcmp(sha1, peeled);
 	} else {
-		commit = lookup_commit_reference_gently(sha1, 1);
-		object = parse_object(sha1);
-		if (!commit || !object)
-			return 0;
-		is_tag = object->type == OBJ_TAG;
+		hashcpy(peeled, sha1);
+		is_tag = 0;
 	}
 
 	/* If --all, then any refs are used.
@@ -142,7 +133,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 		if (!prio)
 			return 0;
 	}
-	add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
+	add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
 	return 0;
 }
 
@@ -228,7 +219,7 @@ static void describe(const char *arg, int last_one)
 	unsigned char sha1[20];
 	struct commit *cmit, *gave_up_on = NULL;
 	struct commit_list *list;
-	struct commit_name *n;
+	struct commit_name *n, *e;
 	struct possible_tag all_matches[MAX_TAGS];
 	unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
 	unsigned long seen_commits = 0;
@@ -240,7 +231,12 @@ static void describe(const char *arg, int last_one)
 	if (!cmit)
 		die("%s is not a valid '%s' object", arg, commit_type);
 
-	n = cmit->util;
+	n = NULL;
+	for (e = names; e; e = e->next) {
+		if (!hashcmp(e->peeled, cmit->object.sha1) &&
+		    replace_name(n, e->prio, e->sha1, &e->tag))
+			n = e;
+	}
 	if (n && (tags || all || n->prio == 2)) {
 		/*
 		 * Exact match to an existing ref.
@@ -259,6 +255,12 @@ static void describe(const char *arg, int last_one)
 	if (debug)
 		fprintf(stderr, "searching to describe %s\n", arg);
 
+	for (e = names; e; e = e->next) {
+		struct commit *c = lookup_commit_reference_gently(e->peeled, 1);
+		if (c && replace_name(c->util, e->prio, e->sha1, &e->tag))
+			c->util = e;
+	}
+
 	list = NULL;
 	cmit->object.flags = SEEN;
 	commit_list_insert(cmit, &list);
@@ -419,7 +421,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 	}
 
 	for_each_rawref(get_name, NULL);
-	if (!found_names && !always)
+	if (!names && !always)
 		die("No names found, cannot describe anything.");
 
 	if (argc == 0) {
-- 
1.7.3.3
Previous: Thomas RastNext: Jonathan Nieder
Message 7 of 28 in “describe: Don’t look up commits with --exact-match”
  1. describe: Don’t look up commits with --exact-matchAnders Kaseorg, Nov 17, 2010
  2. Jonathan NiederDec 3, 2010
  3. Anders KaseorgDec 6, 2010
  4. describe: Don’t look up commits with --exact-matchAnders Kaseorg, Dec 6, 2010
  5. Jonathan NiederDec 6, 2010
  6. Thomas RastDec 6, 2010
  7. Anders KaseorgDec 6, 2010
  8. Jonathan NiederDec 6, 2010
  9. SZEDER GáborDec 7, 2010
  10. 1/2 describe: Use for_each_rawrefAnders Kaseorg, Dec 7, 2010
  11. 2/2 describe: Don’t look up commits with --exact-matchAnders Kaseorg, Dec 7, 2010
  12. Anders KaseorgDec 7, 2010
  13. Junio C HamanoDec 7, 2010
  14. Junio C HamanoDec 7, 2010
  15. Junio C HamanoDec 7, 2010
  16. Anders KaseorgDec 8, 2010
  17. 1/4 describe: Use for_each_rawrefAnders Kaseorg, Dec 8, 2010
  18. 2/4 describe: Don’t use a flex array in struct commit_nameAnders Kaseorg, Dec 8, 2010
  19. 3/4 describe: Store commit_names in a hash table by commit SHA1Anders Kaseorg, Dec 8, 2010
  20. 3/4 describe: Store commit_names in a hash table by commit SHA1Anders Kaseorg, Dec 8, 2010
  21. Junio C HamanoDec 8, 2010
  22. 4/4 describe: Delay looking up commits until searching for an inexact matchAnders Kaseorg, Dec 8, 2010
  23. Junio C HamanoDec 8, 2010
  24. Anders KaseorgDec 8, 2010
  25. 1/4 describe: Use for_each_rawrefAnders Kaseorg, Dec 9, 2010
  26. 2/4 describe: Don’t use a flex array in struct commit_nameAnders Kaseorg, Dec 9, 2010
  27. 3/4 describe: Store commit_names in a hash table by commit SHA1Anders Kaseorg, Dec 9, 2010
  28. 4/4 describe: Delay looking up commits until searching for an inexact matchAnders Kaseorg, Dec 9, 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.