@@ -27,9 +27,16 @@ static const char * const git_tag_usage[] = {
2727 NULL
2828};
2929
30+ #define STRCMP_SORT 0 /* must be zero */
31+ #define VERCMP_SORT 1
32+ #define SORT_MASK 0x7fff
33+ #define REVERSE_SORT 0x8000
34+
3035struct tag_filter {
3136 const char * * patterns ;
3237 int lines ;
38+ int sort ;
39+ struct string_list tags ;
3340 struct commit_list * with_commit ;
3441};
3542
@@ -166,7 +173,10 @@ static int show_reference(const char *refname, const unsigned char *sha1,
166173 return 0 ;
167174
168175 if (!filter -> lines ) {
169- printf ("%s\n" , refname );
176+ if (filter -> sort )
177+ string_list_append (& filter -> tags , refname );
178+ else
179+ printf ("%s\n" , refname );
170180 return 0 ;
171181 }
172182 printf ("%-15s " , refname );
@@ -177,17 +187,39 @@ static int show_reference(const char *refname, const unsigned char *sha1,
177187 return 0 ;
178188}
179189
190+ static int sort_by_version (const void * a_ , const void * b_ )
191+ {
192+ const struct string_list_item * a = a_ ;
193+ const struct string_list_item * b = b_ ;
194+ return versioncmp (a -> string , b -> string );
195+ }
196+
180197static int list_tags (const char * * patterns , int lines ,
181- struct commit_list * with_commit )
198+ struct commit_list * with_commit , int sort )
182199{
183200 struct tag_filter filter ;
184201
185202 filter .patterns = patterns ;
186203 filter .lines = lines ;
204+ filter .sort = sort ;
187205 filter .with_commit = with_commit ;
206+ memset (& filter .tags , 0 , sizeof (filter .tags ));
207+ filter .tags .strdup_strings = 1 ;
188208
189209 for_each_tag_ref (show_reference , (void * ) & filter );
190-
210+ if (sort ) {
211+ int i ;
212+ if ((sort & SORT_MASK ) == VERCMP_SORT )
213+ qsort (filter .tags .items , filter .tags .nr ,
214+ sizeof (struct string_list_item ), sort_by_version );
215+ if (sort & REVERSE_SORT )
216+ for (i = filter .tags .nr - 1 ; i >= 0 ; i -- )
217+ printf ("%s\n" , filter .tags .items [i ].string );
218+ else
219+ for (i = 0 ; i < filter .tags .nr ; i ++ )
220+ printf ("%s\n" , filter .tags .items [i ].string );
221+ string_list_clear (& filter .tags , 0 );
222+ }
191223 return 0 ;
192224}
193225
@@ -427,6 +459,29 @@ static int parse_opt_points_at(const struct option *opt __attribute__((unused)),
427459 return 0 ;
428460}
429461
462+ static int parse_opt_sort (const struct option * opt , const char * arg , int unset )
463+ {
464+ int * sort = opt -> value ;
465+ int flags = 0 ;
466+
467+ if (* arg == '-' ) {
468+ flags |= REVERSE_SORT ;
469+ arg ++ ;
470+ }
471+ if (starts_with (arg , "version:" )) {
472+ * sort = VERCMP_SORT ;
473+ arg += 8 ;
474+ } else if (starts_with (arg , "v:" )) {
475+ * sort = VERCMP_SORT ;
476+ arg += 2 ;
477+ } else
478+ * sort = STRCMP_SORT ;
479+ if (strcmp (arg , "refname" ))
480+ die (_ ("unsupported sort specification %s" ), arg );
481+ * sort |= flags ;
482+ return 0 ;
483+ }
484+
430485int cmd_tag (int argc , const char * * argv , const char * prefix )
431486{
432487 struct strbuf buf = STRBUF_INIT ;
@@ -437,7 +492,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
437492 struct create_tag_options opt ;
438493 char * cleanup_arg = NULL ;
439494 int annotate = 0 , force = 0 , lines = -1 ;
440- int cmdmode = 0 ;
495+ int cmdmode = 0 , sort = 0 ;
441496 const char * msgfile = NULL , * keyid = NULL ;
442497 struct msg_arg msg = { 0 , STRBUF_INIT };
443498 struct commit_list * with_commit = NULL ;
@@ -462,6 +517,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
462517 N_ ("use another key to sign the tag" )),
463518 OPT__FORCE (& force , N_ ("replace the tag if exists" )),
464519 OPT_COLUMN (0 , "column" , & colopts , N_ ("show tag list in columns" )),
520+ {
521+ OPTION_CALLBACK , 0 , "sort" , & sort , N_ ("type" ), N_ ("sort tags" ),
522+ PARSE_OPT_NONEG , parse_opt_sort
523+ },
465524
466525 OPT_GROUP (N_ ("Tag listing options" )),
467526 {
@@ -515,7 +574,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
515574 copts .padding = 2 ;
516575 run_column_filter (colopts , & copts );
517576 }
518- ret = list_tags (argv , lines == -1 ? 0 : lines , with_commit );
577+ if (lines != -1 && sort )
578+ die (_ ("--sort and -n are incompatible" ));
579+ ret = list_tags (argv , lines == -1 ? 0 : lines , with_commit , sort );
519580 if (column_active (colopts ))
520581 stop_column_filter ();
521582 return ret ;
0 commit comments