44#include "tag.h"
55#include "refs.h"
66#include "parse-options.h"
7+ #include "sha1-lookup.h"
78
89#define CUTOFF_DATE_SLOP 86400 /* one day */
910
@@ -96,12 +97,51 @@ static int subpath_matches(const char *path, const char *filter)
9697 return -1 ;
9798}
9899
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+
99111struct name_ref_data {
100112 int tags_only ;
101113 int name_only ;
102114 const char * ref_filter ;
103115};
104116
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+
105145static int name_ref (const char * path , const unsigned char * sha1 , int flags , void * cb_data )
106146{
107147 struct object * o = parse_object (sha1 );
@@ -124,6 +164,8 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
124164 }
125165 }
126166
167+ add_to_tip_table (sha1 , path , can_abbreviate_output );
168+
127169 while (o && o -> type == OBJ_TAG ) {
128170 struct tag * t = (struct tag * ) o ;
129171 if (!t -> tagged )
@@ -134,18 +176,38 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
134176 if (o && o -> type == OBJ_COMMIT ) {
135177 struct commit * commit = (struct commit * )o ;
136178
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 );
144180 name_rev (commit , xstrdup (path ), 0 , 0 , deref );
145181 }
146182 return 0 ;
147183}
148184
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+
149211/* returns a static buffer */
150212static const char * get_rev_name (const struct object * o )
151213{
@@ -154,7 +216,7 @@ static const char *get_rev_name(const struct object *o)
154216 struct commit * c ;
155217
156218 if (o -> type != OBJ_COMMIT )
157- return NULL ;
219+ return get_exact_ref_match ( o ) ;
158220 c = (struct commit * ) o ;
159221 n = c -> util ;
160222 if (!n )
@@ -245,7 +307,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
245307int cmd_name_rev (int argc , const char * * argv , const char * prefix )
246308{
247309 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 ;
249311 struct name_ref_data data = { 0 , 0 , NULL };
250312 struct option opts [] = {
251313 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)
258320 OPT_BOOLEAN (0 , "undefined" , & allow_undefined , N_ ("allow to print `undefined` names" )),
259321 OPT_BOOLEAN (0 , "always" , & always ,
260322 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+ },
261329 OPT_END (),
262330 };
263331
@@ -272,7 +340,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
272340
273341 for (; argc ; argc -- , argv ++ ) {
274342 unsigned char sha1 [20 ];
275- struct object * o ;
343+ struct object * object ;
276344 struct commit * commit ;
277345
278346 if (get_sha1 (* argv , sha1 )) {
@@ -281,17 +349,34 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
281349 continue ;
282350 }
283351
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" ,
287362 * argv );
288363 continue ;
289364 }
290365
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 );
295380 }
296381
297382 if (cutoff )
0 commit comments