@@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
270270 return (ret );
271271}
272272
273- static char * resolve_symref (const char * src , const char * prefix )
274- {
275- unsigned char sha1 [20 ];
276- int flag ;
277- const char * dst ;
278-
279- dst = resolve_ref_unsafe (src , 0 , sha1 , & flag );
280- if (!(dst && (flag & REF_ISSYMREF )))
281- return NULL ;
282- if (prefix )
283- skip_prefix (dst , prefix , & dst );
284- return xstrdup (dst );
285- }
286-
287- static int match_patterns (const char * * pattern , const char * refname )
288- {
289- if (!* pattern )
290- return 1 ; /* no pattern always matches */
291- while (* pattern ) {
292- if (!wildmatch (* pattern , refname , 0 , NULL ))
293- return 1 ;
294- pattern ++ ;
295- }
296- return 0 ;
297- }
298-
299- /*
300- * Allocate memory for a new ref_array_item and insert that into the
301- * given ref_array. Doesn't take the objectname unlike
302- * new_ref_array_item(). This is a temporary function which will be
303- * removed when we port branch.c to use ref-filter APIs.
304- */
305- static struct ref_array_item * ref_array_append (struct ref_array * array , const char * refname )
306- {
307- size_t len = strlen (refname );
308- struct ref_array_item * ref = xcalloc (1 , sizeof (struct ref_array_item ) + len + 1 );
309- memcpy (ref -> refname , refname , len );
310- ref -> refname [len ] = '\0' ;
311- REALLOC_ARRAY (array -> items , array -> nr + 1 );
312- array -> items [array -> nr ++ ] = ref ;
313- return ref ;
314- }
315-
316- static int append_ref (const char * refname , const struct object_id * oid , int flags , void * cb_data )
317- {
318- struct ref_filter_cbdata * cb = (struct ref_filter_cbdata * )(cb_data );
319- struct ref_filter * filter = cb -> filter ;
320- struct ref_array * array = cb -> array ;
321- struct ref_array_item * item ;
322- struct commit * commit ;
323- int kind , i ;
324- const char * prefix , * orig_refname = refname ;
325-
326- static struct {
327- int kind ;
328- const char * prefix ;
329- } ref_kind [] = {
330- { FILTER_REFS_BRANCHES , "refs/heads/" },
331- { FILTER_REFS_REMOTES , "refs/remotes/" },
332- };
333-
334- /* Detect kind */
335- for (i = 0 ; i < ARRAY_SIZE (ref_kind ); i ++ ) {
336- prefix = ref_kind [i ].prefix ;
337- if (skip_prefix (refname , prefix , & refname )) {
338- kind = ref_kind [i ].kind ;
339- break ;
340- }
341- }
342- if (ARRAY_SIZE (ref_kind ) <= i ) {
343- if (!strcmp (refname , "HEAD" ))
344- kind = FILTER_REFS_DETACHED_HEAD ;
345- else
346- return 0 ;
347- }
348-
349- /* Don't add types the caller doesn't want */
350- if ((kind & filter -> kind ) == 0 )
351- return 0 ;
352-
353- if (!match_patterns (filter -> name_patterns , refname ))
354- return 0 ;
355-
356- commit = NULL ;
357- if (filter -> verbose || filter -> with_commit || filter -> merge != REF_FILTER_MERGED_NONE ) {
358- commit = lookup_commit_reference_gently (oid -> hash , 1 );
359- if (!commit )
360- return 0 ;
361-
362- /* Filter with with_commit if specified */
363- if (!is_descendant_of (commit , filter -> with_commit ))
364- return 0 ;
365-
366- if (filter -> merge != REF_FILTER_MERGED_NONE )
367- add_pending_object (array -> revs ,
368- (struct object * )commit , refname );
369- }
370-
371- item = ref_array_append (array , refname );
372-
373- /* Record the new item */
374- item -> kind = kind ;
375- item -> commit = commit ;
376- item -> symref = resolve_symref (orig_refname , prefix );
377- item -> ignore = 0 ;
378-
379- return 0 ;
380- }
381-
382- static int ref_cmp (const void * r1 , const void * r2 )
383- {
384- struct ref_array_item * c1 = * ((struct ref_array_item * * )r1 );
385- struct ref_array_item * c2 = * ((struct ref_array_item * * )r2 );
386-
387- if (c1 -> kind != c2 -> kind )
388- return c1 -> kind - c2 -> kind ;
389- return strcmp (c1 -> refname , c2 -> refname );
390- }
391-
392273static void fill_tracking_info (struct strbuf * stat , const char * branch_name ,
393274 int show_upstream_ref )
394275{
@@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
452333}
453334
454335static void add_verbose_info (struct strbuf * out , struct ref_array_item * item ,
455- struct ref_filter * filter )
336+ struct ref_filter * filter , const char * refname )
456337{
457338 struct strbuf subject = STRBUF_INIT , stat = STRBUF_INIT ;
458339 const char * sub = _ (" **** invalid ref ****" );
@@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
464345 }
465346
466347 if (item -> kind == FILTER_REFS_BRANCHES )
467- fill_tracking_info (& stat , item -> refname , filter -> verbose > 1 );
348+ fill_tracking_info (& stat , refname , filter -> verbose > 1 );
468349
469350 strbuf_addf (out , " %s %s%s" ,
470351 find_unique_abbrev (item -> commit -> object .sha1 , filter -> abbrev ),
@@ -504,8 +385,8 @@ static char *get_head_description(void)
504385 return strbuf_detach (& desc , NULL );
505386}
506387
507- static void print_ref_item (struct ref_array_item * item , int maxwidth ,
508- struct ref_filter * filter , const char * remote_prefix )
388+ static void format_and_print_ref_item (struct ref_array_item * item , int maxwidth ,
389+ struct ref_filter * filter , const char * remote_prefix )
509390{
510391 char c ;
511392 int current = 0 ;
@@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
515396 const char * desc = item -> refname ;
516397 char * to_free = NULL ;
517398
518- if (item -> ignore )
519- return ;
520-
521399 switch (item -> kind ) {
522400 case FILTER_REFS_BRANCHES :
523- if (!filter -> detached && !strcmp (item -> refname , head ))
401+ skip_prefix (desc , "refs/heads/" , & desc );
402+ if (!filter -> detached && !strcmp (desc , head ))
524403 current = 1 ;
525404 else
526405 color = BRANCH_COLOR_LOCAL ;
527406 break ;
528407 case FILTER_REFS_REMOTES :
408+ skip_prefix (desc , "refs/remotes/" , & desc );
529409 color = BRANCH_COLOR_REMOTE ;
530410 prefix = remote_prefix ;
531411 break ;
@@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,
554434 strbuf_addf (& out , "%c %s%s%s" , c , branch_get_color (color ),
555435 name .buf , branch_get_color (BRANCH_COLOR_RESET ));
556436
557- if (item -> symref )
558- strbuf_addf (& out , " -> %s" , item -> symref );
437+ if (item -> symref ) {
438+ skip_prefix (item -> symref , "refs/remotes/" , & desc );
439+ strbuf_addf (& out , " -> %s" , desc );
440+ }
559441 else if (filter -> verbose )
560442 /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
561- add_verbose_info (& out , item , filter );
443+ add_verbose_info (& out , item , filter , desc );
562444 if (column_active (colopts )) {
563445 assert (!filter -> verbose && "--column and --verbose are incompatible" );
564446 string_list_append (& output , out .buf );
@@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
575457 int i , max = 0 ;
576458 for (i = 0 ; i < refs -> nr ; i ++ ) {
577459 struct ref_array_item * it = refs -> items [i ];
460+ const char * desc = it -> refname ;
578461 int w ;
579462
580- if (it -> ignore )
581- continue ;
582- w = utf8_strwidth (it -> refname );
463+ skip_prefix (it -> refname , "refs/heads/" , & desc );
464+ skip_prefix (it -> refname , "refs/remotes/" , & desc );
465+ w = utf8_strwidth (desc );
466+
583467 if (it -> kind == FILTER_REFS_REMOTES )
584468 w += remote_bonus ;
585469 if (w > max )
@@ -588,14 +472,12 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
588472 return max ;
589473}
590474
591- static void print_ref_list (struct ref_filter * filter )
475+ static void print_ref_list (struct ref_filter * filter , struct ref_sorting * sorting )
592476{
593477 int i ;
594478 struct ref_array array ;
595- struct ref_filter_cbdata data ;
596479 int maxwidth = 0 ;
597480 const char * remote_prefix = "" ;
598- struct rev_info revs ;
599481
600482 /*
601483 * If we are listing more than just remote branches,
@@ -606,54 +488,26 @@ static void print_ref_list(struct ref_filter *filter)
606488 remote_prefix = "remotes/" ;
607489
608490 memset (& array , 0 , sizeof (array ));
609- if (filter -> merge != REF_FILTER_MERGED_NONE )
610- init_revisions (& revs , NULL );
611-
612- data .array = & array ;
613- data .filter = filter ;
614- array .revs = & revs ;
615-
616- /*
617- * First we obtain all regular branch refs and if the HEAD is
618- * detached then we insert that ref to the end of the ref_fist
619- * so that it can be printed and removed first.
620- */
621- for_each_rawref (append_ref , & data );
622- if (filter -> detached )
623- head_ref (append_ref , & data );
624- /*
625- * The following implementation is currently duplicated in ref-filter. It
626- * will eventually be removed when we port branch.c to use ref-filter APIs.
627- */
628- if (filter -> merge != REF_FILTER_MERGED_NONE ) {
629- filter -> merge_commit -> object .flags |= UNINTERESTING ;
630- add_pending_object (& revs , & filter -> merge_commit -> object , "" );
631- revs .limited = 1 ;
632-
633- if (prepare_revision_walk (& revs ))
634- die (_ ("revision walk setup failed" ));
635-
636- for (i = 0 ; i < array .nr ; i ++ ) {
637- struct ref_array_item * item = array .items [i ];
638- struct commit * commit = item -> commit ;
639- int is_merged = !!(commit -> object .flags & UNINTERESTING );
640- item -> ignore = is_merged != (filter -> merge == REF_FILTER_MERGED_INCLUDE );
641- }
642491
643- for (i = 0 ; i < array .nr ; i ++ ) {
644- struct ref_array_item * item = array .items [i ];
645- clear_commit_marks (item -> commit , ALL_REV_FLAGS );
646- }
647- clear_commit_marks (filter -> merge_commit , ALL_REV_FLAGS );
648- }
492+ verify_ref_format ("%(refname)%(symref)" );
493+ filter_refs (& array , filter , filter -> kind | FILTER_REFS_INCLUDE_BROKEN );
649494
650495 if (filter -> verbose )
651496 maxwidth = calc_maxwidth (& array , strlen (remote_prefix ));
652497
653- qsort (array .items , array .nr , sizeof (struct ref_array_item * ), ref_cmp );
498+ /*
499+ * If no sorting parameter is given then we default to sorting
500+ * by 'refname'. This would give us an alphabetically sorted
501+ * array with the 'HEAD' ref at the beginning followed by
502+ * local branches 'refs/heads/...' and finally remote-tacking
503+ * branches 'refs/remotes/...'.
504+ */
505+ if (!sorting )
506+ sorting = ref_default_sorting ();
507+ ref_array_sort (sorting , & array );
654508
655509 for (i = 0 ; i < array .nr ; i ++ )
656- print_ref_item (array .items [i ], maxwidth , filter , remote_prefix );
510+ format_and_print_ref_item (array .items [i ], maxwidth , filter , remote_prefix );
657511
658512 ref_array_clear (& array );
659513}
@@ -755,6 +609,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
755609 const char * new_upstream = NULL ;
756610 enum branch_track track ;
757611 struct ref_filter filter ;
612+ static struct ref_sorting * sorting = NULL , * * sorting_tail = & sorting ;
758613
759614 struct option options [] = {
760615 OPT_GROUP (N_ ("Generic options" )),
@@ -789,6 +644,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
789644 OPT_MERGED (& filter , N_ ("print only branches that are merged" )),
790645 OPT_NO_MERGED (& filter , N_ ("print only branches that are not merged" )),
791646 OPT_COLUMN (0 , "column" , & colopts , N_ ("list branches in columns" )),
647+ OPT_CALLBACK (0 , "sort" , sorting_tail , N_ ("key" ),
648+ N_ ("field name to sort on" ), & parse_opt_ref_sorting ),
792649 OPT_END (),
793650 };
794651
@@ -847,7 +704,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
847704 if ((filter .kind & FILTER_REFS_BRANCHES ) && filter .detached )
848705 filter .kind |= FILTER_REFS_DETACHED_HEAD ;
849706 filter .name_patterns = argv ;
850- print_ref_list (& filter );
707+ print_ref_list (& filter , sorting );
851708 print_columns (& output , colopts , NULL );
852709 string_list_clear (& output , 0 );
853710 return 0 ;
0 commit comments