66#include "exec_cmd.h"
77#include "parse-options.h"
88#include "diff.h"
9+ #include "hash.h"
910
1011#define SEEN (1u<<0)
1112#define MAX_TAGS (FLAG_BITS - 1)
@@ -22,7 +23,8 @@ static int tags; /* Allow lightweight tags */
2223static int longformat ;
2324static int abbrev = DEFAULT_ABBREV ;
2425static int max_candidates = 10 ;
25- static int found_names ;
26+ static struct hash_table names ;
27+ static int have_util ;
2628static const char * pattern ;
2729static int always ;
2830static const char * dirty ;
@@ -34,16 +36,44 @@ static const char *diff_index_args[] = {
3436
3537
3638struct commit_name {
39+ struct commit_name * next ;
40+ unsigned char peeled [20 ];
3741 struct tag * tag ;
3842 unsigned prio :2 ; /* annotated tag = 2, tag = 1, head = 0 */
3943 unsigned name_checked :1 ;
4044 unsigned char sha1 [20 ];
41- char path [ FLEX_ARRAY ]; /* more */
45+ const char * path ;
4246};
4347static const char * prio_names [] = {
4448 "head" , "lightweight" , "annotated" ,
4549};
4650
51+ static inline unsigned int hash_sha1 (const unsigned char * sha1 )
52+ {
53+ unsigned int hash ;
54+ memcpy (& hash , sha1 , sizeof (hash ));
55+ return hash ;
56+ }
57+
58+ static inline struct commit_name * find_commit_name (const unsigned char * peeled )
59+ {
60+ struct commit_name * n = lookup_hash (hash_sha1 (peeled ), & names );
61+ while (n && !!hashcmp (peeled , n -> peeled ))
62+ n = n -> next ;
63+ return n ;
64+ }
65+
66+ static int set_util (void * chain )
67+ {
68+ struct commit_name * n ;
69+ for (n = chain ; n ; n = n -> next ) {
70+ struct commit * c = lookup_commit_reference_gently (n -> peeled , 1 );
71+ if (c )
72+ c -> util = n ;
73+ }
74+ return 0 ;
75+ }
76+
4777static int replace_name (struct commit_name * e ,
4878 int prio ,
4979 const unsigned char * sha1 ,
@@ -78,48 +108,47 @@ static int replace_name(struct commit_name *e,
78108}
79109
80110static void add_to_known_names (const char * path ,
81- struct commit * commit ,
111+ const unsigned char * peeled ,
82112 int prio ,
83113 const unsigned char * sha1 )
84114{
85- struct commit_name * e = commit -> util ;
115+ struct commit_name * e = find_commit_name ( peeled ) ;
86116 struct tag * tag = NULL ;
87117 if (replace_name (e , prio , sha1 , & tag )) {
88- size_t len = strlen (path )+ 1 ;
89- free (e );
90- e = xmalloc (sizeof (struct commit_name ) + len );
118+ if (!e ) {
119+ void * * pos ;
120+ e = xmalloc (sizeof (struct commit_name ));
121+ hashcpy (e -> peeled , peeled );
122+ pos = insert_hash (hash_sha1 (peeled ), e , & names );
123+ if (pos ) {
124+ e -> next = * pos ;
125+ * pos = e ;
126+ } else {
127+ e -> next = NULL ;
128+ }
129+ }
91130 e -> tag = tag ;
92131 e -> prio = prio ;
93132 e -> name_checked = 0 ;
94133 hashcpy (e -> sha1 , sha1 );
95- memcpy (e -> path , path , len );
96- commit -> util = e ;
134+ e -> path = path ;
97135 }
98- found_names = 1 ;
99136}
100137
101138static int get_name (const char * path , const unsigned char * sha1 , int flag , void * cb_data )
102139{
103140 int might_be_tag = !prefixcmp (path , "refs/tags/" );
104- struct commit * commit ;
105- struct object * object ;
106141 unsigned char peeled [20 ];
107142 int is_tag , prio ;
108143
109144 if (!all && !might_be_tag )
110145 return 0 ;
111146
112147 if (!peel_ref (path , peeled ) && !is_null_sha1 (peeled )) {
113- commit = lookup_commit_reference_gently (peeled , 1 );
114- if (!commit )
115- return 0 ;
116- is_tag = !!hashcmp (sha1 , commit -> object .sha1 );
148+ is_tag = !!hashcmp (sha1 , peeled );
117149 } else {
118- commit = lookup_commit_reference_gently (sha1 , 1 );
119- object = parse_object (sha1 );
120- if (!commit || !object )
121- return 0 ;
122- is_tag = object -> type == OBJ_TAG ;
150+ hashcpy (peeled , sha1 );
151+ is_tag = 0 ;
123152 }
124153
125154 /* If --all, then any refs are used.
@@ -142,7 +171,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
142171 if (!prio )
143172 return 0 ;
144173 }
145- add_to_known_names (all ? path + 5 : path + 10 , commit , prio , sha1 );
174+ add_to_known_names (all ? path + 5 : path + 10 , peeled , prio , sha1 );
146175 return 0 ;
147176}
148177
@@ -240,7 +269,7 @@ static void describe(const char *arg, int last_one)
240269 if (!cmit )
241270 die ("%s is not a valid '%s' object" , arg , commit_type );
242271
243- n = cmit -> util ;
272+ n = find_commit_name ( cmit -> object . sha1 ) ;
244273 if (n && (tags || all || n -> prio == 2 )) {
245274 /*
246275 * Exact match to an existing ref.
@@ -259,6 +288,11 @@ static void describe(const char *arg, int last_one)
259288 if (debug )
260289 fprintf (stderr , "searching to describe %s\n" , arg );
261290
291+ if (!have_util ) {
292+ for_each_hash (& names , set_util );
293+ have_util = 1 ;
294+ }
295+
262296 list = NULL ;
263297 cmit -> object .flags = SEEN ;
264298 commit_list_insert (cmit , & list );
@@ -418,8 +452,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
418452 return cmd_name_rev (i + argc , args , prefix );
419453 }
420454
421- for_each_ref (get_name , NULL );
422- if (!found_names && !always )
455+ init_hash (& names );
456+ for_each_rawref (get_name , NULL );
457+ if (!names .nr && !always )
423458 die ("No names found, cannot describe anything." );
424459
425460 if (argc == 0 ) {
0 commit comments