6
6
#include "exec_cmd.h"
7
7
#include "parse-options.h"
8
8
#include "diff.h"
9
+ #include "hash.h"
9
10
10
11
#define SEEN (1u<<0)
11
12
#define MAX_TAGS (FLAG_BITS - 1)
@@ -22,7 +23,8 @@ static int tags; /* Allow lightweight tags */
22
23
static int longformat ;
23
24
static int abbrev = DEFAULT_ABBREV ;
24
25
static int max_candidates = 10 ;
25
- static int found_names ;
26
+ static struct hash_table names ;
27
+ static int have_util ;
26
28
static const char * pattern ;
27
29
static int always ;
28
30
static const char * dirty ;
@@ -34,16 +36,44 @@ static const char *diff_index_args[] = {
34
36
35
37
36
38
struct commit_name {
39
+ struct commit_name * next ;
40
+ unsigned char peeled [20 ];
37
41
struct tag * tag ;
38
42
unsigned prio :2 ; /* annotated tag = 2, tag = 1, head = 0 */
39
43
unsigned name_checked :1 ;
40
44
unsigned char sha1 [20 ];
41
- char path [ FLEX_ARRAY ]; /* more */
45
+ const char * path ;
42
46
};
43
47
static const char * prio_names [] = {
44
48
"head" , "lightweight" , "annotated" ,
45
49
};
46
50
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
+
47
77
static int replace_name (struct commit_name * e ,
48
78
int prio ,
49
79
const unsigned char * sha1 ,
@@ -78,48 +108,47 @@ static int replace_name(struct commit_name *e,
78
108
}
79
109
80
110
static void add_to_known_names (const char * path ,
81
- struct commit * commit ,
111
+ const unsigned char * peeled ,
82
112
int prio ,
83
113
const unsigned char * sha1 )
84
114
{
85
- struct commit_name * e = commit -> util ;
115
+ struct commit_name * e = find_commit_name ( peeled ) ;
86
116
struct tag * tag = NULL ;
87
117
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
+ }
91
130
e -> tag = tag ;
92
131
e -> prio = prio ;
93
132
e -> name_checked = 0 ;
94
133
hashcpy (e -> sha1 , sha1 );
95
- memcpy (e -> path , path , len );
96
- commit -> util = e ;
134
+ e -> path = path ;
97
135
}
98
- found_names = 1 ;
99
136
}
100
137
101
138
static int get_name (const char * path , const unsigned char * sha1 , int flag , void * cb_data )
102
139
{
103
140
int might_be_tag = !prefixcmp (path , "refs/tags/" );
104
- struct commit * commit ;
105
- struct object * object ;
106
141
unsigned char peeled [20 ];
107
142
int is_tag , prio ;
108
143
109
144
if (!all && !might_be_tag )
110
145
return 0 ;
111
146
112
147
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 );
117
149
} 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 ;
123
152
}
124
153
125
154
/* 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
142
171
if (!prio )
143
172
return 0 ;
144
173
}
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 );
146
175
return 0 ;
147
176
}
148
177
@@ -240,7 +269,7 @@ static void describe(const char *arg, int last_one)
240
269
if (!cmit )
241
270
die ("%s is not a valid '%s' object" , arg , commit_type );
242
271
243
- n = cmit -> util ;
272
+ n = find_commit_name ( cmit -> object . sha1 ) ;
244
273
if (n && (tags || all || n -> prio == 2 )) {
245
274
/*
246
275
* Exact match to an existing ref.
@@ -259,6 +288,11 @@ static void describe(const char *arg, int last_one)
259
288
if (debug )
260
289
fprintf (stderr , "searching to describe %s\n" , arg );
261
290
291
+ if (!have_util ) {
292
+ for_each_hash (& names , set_util );
293
+ have_util = 1 ;
294
+ }
295
+
262
296
list = NULL ;
263
297
cmit -> object .flags = SEEN ;
264
298
commit_list_insert (cmit , & list );
@@ -418,8 +452,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
418
452
return cmd_name_rev (i + argc , args , prefix );
419
453
}
420
454
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 )
423
458
die ("No names found, cannot describe anything." );
424
459
425
460
if (argc == 0 ) {
0 commit comments