4
4
#include "tag.h"
5
5
#include "refs.h"
6
6
#include "parse-options.h"
7
+ #include "sha1-lookup.h"
7
8
8
9
#define CUTOFF_DATE_SLOP 86400 /* one day */
9
10
@@ -96,12 +97,51 @@ static int subpath_matches(const char *path, const char *filter)
96
97
return -1 ;
97
98
}
98
99
100
+ static const char * name_ref_abbrev (const char * refname , int shorten_unambiguous )
101
+ {
102
+ if (shorten_unambiguous )
103
+ refname = shorten_unambiguous_ref (refname , 0 );
104
+ else if (!prefixcmp (refname , "refs/heads/" ))
105
+ refname = refname + 11 ;
106
+ else if (!prefixcmp (refname , "refs/" ))
107
+ refname = refname + 5 ;
108
+ return refname ;
109
+ }
110
+
99
111
struct name_ref_data {
100
112
int tags_only ;
101
113
int name_only ;
102
114
const char * ref_filter ;
103
115
};
104
116
117
+ static struct tip_table {
118
+ struct tip_table_entry {
119
+ unsigned char sha1 [20 ];
120
+ const char * refname ;
121
+ } * table ;
122
+ int nr ;
123
+ int alloc ;
124
+ int sorted ;
125
+ } tip_table ;
126
+
127
+ static void add_to_tip_table (const unsigned char * sha1 , const char * refname ,
128
+ int shorten_unambiguous )
129
+ {
130
+ refname = name_ref_abbrev (refname , shorten_unambiguous );
131
+
132
+ ALLOC_GROW (tip_table .table , tip_table .nr + 1 , tip_table .alloc );
133
+ hashcpy (tip_table .table [tip_table .nr ].sha1 , sha1 );
134
+ tip_table .table [tip_table .nr ].refname = xstrdup (refname );
135
+ tip_table .nr ++ ;
136
+ tip_table .sorted = 0 ;
137
+ }
138
+
139
+ static int tipcmp (const void * a_ , const void * b_ )
140
+ {
141
+ const struct tip_table_entry * a = a_ , * b = b_ ;
142
+ return hashcmp (a -> sha1 , b -> sha1 );
143
+ }
144
+
105
145
static int name_ref (const char * path , const unsigned char * sha1 , int flags , void * cb_data )
106
146
{
107
147
struct object * o = parse_object (sha1 );
@@ -124,6 +164,8 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
124
164
}
125
165
}
126
166
167
+ add_to_tip_table (sha1 , path , can_abbreviate_output );
168
+
127
169
while (o && o -> type == OBJ_TAG ) {
128
170
struct tag * t = (struct tag * ) o ;
129
171
if (!t -> tagged )
@@ -134,18 +176,38 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
134
176
if (o && o -> type == OBJ_COMMIT ) {
135
177
struct commit * commit = (struct commit * )o ;
136
178
137
- if (can_abbreviate_output )
138
- path = shorten_unambiguous_ref (path , 0 );
139
- else if (!prefixcmp (path , "refs/heads/" ))
140
- path = path + 11 ;
141
- else if (!prefixcmp (path , "refs/" ))
142
- path = path + 5 ;
143
-
179
+ path = name_ref_abbrev (path , can_abbreviate_output );
144
180
name_rev (commit , xstrdup (path ), 0 , 0 , deref );
145
181
}
146
182
return 0 ;
147
183
}
148
184
185
+ static const unsigned char * nth_tip_table_ent (size_t ix , void * table_ )
186
+ {
187
+ struct tip_table_entry * table = table_ ;
188
+ return table [ix ].sha1 ;
189
+ }
190
+
191
+ static const char * get_exact_ref_match (const struct object * o )
192
+ {
193
+ int found ;
194
+
195
+ if (!tip_table .table || !tip_table .nr )
196
+ return NULL ;
197
+
198
+ if (!tip_table .sorted ) {
199
+ qsort (tip_table .table , tip_table .nr , sizeof (* tip_table .table ),
200
+ tipcmp );
201
+ tip_table .sorted = 1 ;
202
+ }
203
+
204
+ found = sha1_pos (o -> sha1 , tip_table .table , tip_table .nr ,
205
+ nth_tip_table_ent );
206
+ if (0 <= found )
207
+ return tip_table .table [found ].refname ;
208
+ return NULL ;
209
+ }
210
+
149
211
/* returns a static buffer */
150
212
static const char * get_rev_name (const struct object * o )
151
213
{
@@ -154,7 +216,7 @@ static const char *get_rev_name(const struct object *o)
154
216
struct commit * c ;
155
217
156
218
if (o -> type != OBJ_COMMIT )
157
- return NULL ;
219
+ return get_exact_ref_match ( o ) ;
158
220
c = (struct commit * ) o ;
159
221
n = c -> util ;
160
222
if (!n )
@@ -245,7 +307,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
245
307
int cmd_name_rev (int argc , const char * * argv , const char * prefix )
246
308
{
247
309
struct object_array revs = OBJECT_ARRAY_INIT ;
248
- int all = 0 , transform_stdin = 0 , allow_undefined = 1 , always = 0 ;
310
+ int all = 0 , transform_stdin = 0 , allow_undefined = 1 , always = 0 , peel_tag = 0 ;
249
311
struct name_ref_data data = { 0 , 0 , NULL };
250
312
struct option opts [] = {
251
313
OPT_BOOLEAN (0 , "name-only" , & data .name_only , N_ ("print only names (no SHA-1)" )),
@@ -258,6 +320,12 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
258
320
OPT_BOOLEAN (0 , "undefined" , & allow_undefined , N_ ("allow to print `undefined` names" )),
259
321
OPT_BOOLEAN (0 , "always" , & always ,
260
322
N_ ("show abbreviated commit object as fallback" )),
323
+ {
324
+ /* A Hidden OPT_BOOL */
325
+ OPTION_SET_INT , 0 , "peel-tag" , & peel_tag , NULL ,
326
+ N_ ("dereference tags in the input (internal use)" ),
327
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN , NULL , 1 ,
328
+ },
261
329
OPT_END (),
262
330
};
263
331
@@ -272,7 +340,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
272
340
273
341
for (; argc ; argc -- , argv ++ ) {
274
342
unsigned char sha1 [20 ];
275
- struct object * o ;
343
+ struct object * object ;
276
344
struct commit * commit ;
277
345
278
346
if (get_sha1 (* argv , sha1 )) {
@@ -281,17 +349,34 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
281
349
continue ;
282
350
}
283
351
284
- o = deref_tag (parse_object (sha1 ), * argv , 0 );
285
- if (!o || o -> type != OBJ_COMMIT ) {
286
- fprintf (stderr , "Could not get commit for %s. Skipping.\n" ,
352
+ commit = NULL ;
353
+ object = parse_object (sha1 );
354
+ if (object ) {
355
+ struct object * peeled = deref_tag (object , * argv , 0 );
356
+ if (peeled && peeled -> type == OBJ_COMMIT )
357
+ commit = (struct commit * )peeled ;
358
+ }
359
+
360
+ if (!object ) {
361
+ fprintf (stderr , "Could not get object for %s. Skipping.\n" ,
287
362
* argv );
288
363
continue ;
289
364
}
290
365
291
- commit = (struct commit * )o ;
292
- if (cutoff > commit -> date )
293
- cutoff = commit -> date ;
294
- add_object_array ((struct object * )commit , * argv , & revs );
366
+ if (commit ) {
367
+ if (cutoff > commit -> date )
368
+ cutoff = commit -> date ;
369
+ }
370
+
371
+ if (peel_tag ) {
372
+ if (!commit ) {
373
+ fprintf (stderr , "Could not get commit for %s. Skipping.\n" ,
374
+ * argv );
375
+ continue ;
376
+ }
377
+ object = (struct object * )commit ;
378
+ }
379
+ add_object_array (object , * argv , & revs );
295
380
}
296
381
297
382
if (cutoff )
0 commit comments