Skip to content

Commit

Permalink
describe: Store commit_names in a hash table by commit SHA1
Browse files Browse the repository at this point in the history
describe is currently forced to look up the commit at each tag in
order to store the struct commit_name pointers in struct commit.util.
For --exact-match queries, those lookups are wasteful.  In preparation
for removing them, put the commit_names into a hash table, indexed by
commit SHA1, that can be used to quickly check for exact matches.

Signed-off-by: Anders Kaseorg <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
andersk authored and gitster committed Dec 9, 2010
1 parent 1e1ade1 commit 3cfa4db
Showing 1 changed file with 33 additions and 5 deletions.
38 changes: 33 additions & 5 deletions builtin/describe.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "exec_cmd.h"
#include "parse-options.h"
#include "diff.h"
#include "hash.h"

#define SEEN (1u<<0)
#define MAX_TAGS (FLAG_BITS - 1)
Expand All @@ -22,7 +23,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 hash_table names;
static const char *pattern;
static int always;
static const char *dirty;
Expand All @@ -34,6 +35,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;
Expand All @@ -44,6 +47,21 @@ static const char *prio_names[] = {
"head", "lightweight", "annotated",
};

static inline unsigned int hash_sha1(const unsigned char *sha1)
{
unsigned int hash;
memcpy(&hash, sha1, sizeof(hash));
return hash;
}

static inline struct commit_name *find_commit_name(const unsigned char *peeled)
{
struct commit_name *n = lookup_hash(hash_sha1(peeled), &names);
while (n && !!hashcmp(peeled, n->peeled))
n = n->next;
return n;
}

static int replace_name(struct commit_name *e,
int prio,
const unsigned char *sha1,
Expand Down Expand Up @@ -82,20 +100,29 @@ static void add_to_known_names(const char *path,
int prio,
const unsigned char *sha1)
{
struct commit_name *e = commit->util;
const unsigned char *peeled = commit->object.sha1;
struct commit_name *e = find_commit_name(peeled);
struct tag *tag = NULL;
if (replace_name(e, prio, sha1, &tag)) {
if (!e) {
void **pos;
e = xmalloc(sizeof(struct commit_name));
commit->util = e;
hashcpy(e->peeled, peeled);
pos = insert_hash(hash_sha1(peeled), e, &names);
if (pos) {
e->next = *pos;
*pos = e;
} else {
e->next = NULL;
}
}
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
hashcpy(e->sha1, sha1);
e->path = path;
}
found_names = 1;
}

static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
Expand Down Expand Up @@ -240,7 +267,7 @@ 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 = find_commit_name(cmit->object.sha1);
if (n && (tags || all || n->prio == 2)) {
/*
* Exact match to an existing ref.
Expand Down Expand Up @@ -418,8 +445,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
return cmd_name_rev(i + argc, args, prefix);
}

init_hash(&names);
for_each_rawref(get_name, NULL);
if (!found_names && !always)
if (!names.nr && !always)
die("No names found, cannot describe anything.");

if (argc == 0) {
Expand Down

0 comments on commit 3cfa4db

Please sign in to comment.