@@ -21,6 +21,7 @@ static const char * const builtin_remote_usage[] = {
2121
2222#define GET_REF_STATES (1<<0)
2323#define GET_HEAD_NAMES (1<<1)
24+ #define GET_PUSH_REF_STATES (1<<2)
2425
2526static int verbose ;
2627
@@ -220,7 +221,7 @@ static void read_branches(void)
220221
221222struct ref_states {
222223 struct remote * remote ;
223- struct string_list new , stale , tracked , heads ;
224+ struct string_list new , stale , tracked , heads , push ;
224225 int queried ;
225226};
226227
@@ -275,6 +276,112 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
275276 return 0 ;
276277}
277278
279+ struct push_info {
280+ char * dest ;
281+ int forced ;
282+ enum {
283+ PUSH_STATUS_CREATE = 0 ,
284+ PUSH_STATUS_DELETE ,
285+ PUSH_STATUS_UPTODATE ,
286+ PUSH_STATUS_FASTFORWARD ,
287+ PUSH_STATUS_OUTOFDATE ,
288+ PUSH_STATUS_NOTQUERIED ,
289+ } status ;
290+ };
291+
292+ static int get_push_ref_states (const struct ref * remote_refs ,
293+ struct ref_states * states )
294+ {
295+ struct remote * remote = states -> remote ;
296+ struct ref * ref , * local_refs , * push_map , * * push_tail ;
297+ if (remote -> mirror )
298+ return 0 ;
299+
300+ local_refs = get_local_heads ();
301+ ref = push_map = copy_ref_list (remote_refs );
302+ while (ref -> next )
303+ ref = ref -> next ;
304+ push_tail = & ref -> next ;
305+
306+ match_refs (local_refs , push_map , & push_tail , remote -> push_refspec_nr ,
307+ remote -> push_refspec , MATCH_REFS_NONE );
308+
309+ states -> push .strdup_strings = 1 ;
310+ for (ref = push_map ; ref ; ref = ref -> next ) {
311+ struct string_list_item * item ;
312+ struct push_info * info ;
313+
314+ if (!ref -> peer_ref )
315+ continue ;
316+ hashcpy (ref -> new_sha1 , ref -> peer_ref -> new_sha1 );
317+
318+ item = string_list_append (abbrev_branch (ref -> peer_ref -> name ),
319+ & states -> push );
320+ item -> util = xcalloc (sizeof (struct push_info ), 1 );
321+ info = item -> util ;
322+ info -> forced = ref -> force ;
323+ info -> dest = xstrdup (abbrev_branch (ref -> name ));
324+
325+ if (is_null_sha1 (ref -> new_sha1 )) {
326+ info -> status = PUSH_STATUS_DELETE ;
327+ } else if (!hashcmp (ref -> old_sha1 , ref -> new_sha1 ))
328+ info -> status = PUSH_STATUS_UPTODATE ;
329+ else if (is_null_sha1 (ref -> old_sha1 ))
330+ info -> status = PUSH_STATUS_CREATE ;
331+ else if (has_sha1_file (ref -> old_sha1 ) &&
332+ ref_newer (ref -> new_sha1 , ref -> old_sha1 ))
333+ info -> status = PUSH_STATUS_FASTFORWARD ;
334+ else
335+ info -> status = PUSH_STATUS_OUTOFDATE ;
336+ // ref->peer_ref = NULL; /* local ref which is freed below */
337+ }
338+ free_refs (local_refs );
339+ free_refs (push_map );
340+ return 0 ;
341+ }
342+
343+ static int get_push_ref_states_noquery (struct ref_states * states )
344+ {
345+ int i ;
346+ struct remote * remote = states -> remote ;
347+ struct string_list_item * item ;
348+ struct push_info * info ;
349+
350+ if (remote -> mirror )
351+ return 0 ;
352+
353+ states -> push .strdup_strings = 1 ;
354+ if (!remote -> push_refspec_nr ) {
355+ item = string_list_append ("(matching)" , & states -> push );
356+ info = item -> util = xcalloc (sizeof (struct push_info ), 1 );
357+ info -> status = PUSH_STATUS_NOTQUERIED ;
358+ info -> dest = xstrdup (item -> string );
359+ }
360+ for (i = 0 ; i < remote -> push_refspec_nr ; i ++ ) {
361+ struct refspec * spec = remote -> push + i ;
362+ char buf [PATH_MAX ];
363+ if (spec -> matching )
364+ item = string_list_append ("(matching)" , & states -> push );
365+ else if (spec -> pattern ) {
366+ snprintf (buf , (sizeof (buf )), "%s*" , spec -> src );
367+ item = string_list_append (buf , & states -> push );
368+ snprintf (buf , (sizeof (buf )), "%s*" , spec -> dst );
369+ } else if (strlen (spec -> src ))
370+ item = string_list_append (spec -> src , & states -> push );
371+ else
372+ item = string_list_append ("(delete)" , & states -> push );
373+
374+ info = item -> util = xcalloc (sizeof (struct push_info ), 1 );
375+ info -> forced = spec -> force ;
376+ info -> status = PUSH_STATUS_NOTQUERIED ;
377+ if (spec -> pattern )
378+ info -> dest = xstrdup (buf );
379+ else
380+ info -> dest = xstrdup (spec -> dst ? spec -> dst : item -> string );
381+ }
382+ return 0 ;
383+ }
384+
278385static int get_head_names (const struct ref * remote_refs , struct ref_states * states )
279386{
280387 struct ref * ref , * matches ;
@@ -644,12 +751,20 @@ static int rm(int argc, const char **argv)
644751 return result ;
645752}
646753
754+ void clear_push_info (void * util , const char * string )
755+ {
756+ struct push_info * info = util ;
757+ free (info -> dest );
758+ free (info );
759+ }
760+
647761static void free_remote_ref_states (struct ref_states * states )
648762{
649763 string_list_clear (& states -> new , 0 );
650764 string_list_clear (& states -> stale , 0 );
651765 string_list_clear (& states -> tracked , 0 );
652766 string_list_clear (& states -> heads , 0 );
767+ string_list_clear_func (& states -> push , clear_push_info );
653768}
654769
655770static int append_ref_to_tracked_list (const char * refname ,
@@ -693,9 +808,12 @@ static int get_remote_ref_states(const char *name,
693808 get_ref_states (remote_refs , states );
694809 if (query & GET_HEAD_NAMES )
695810 get_head_names (remote_refs , states );
811+ if (query & GET_PUSH_REF_STATES )
812+ get_push_ref_states (remote_refs , states );
696813 } else {
697814 for_each_ref (append_ref_to_tracked_list , states );
698815 sort_string_list (& states -> tracked );
816+ get_push_ref_states_noquery (states );
699817 }
700818
701819 return 0 ;
@@ -704,7 +822,7 @@ static int get_remote_ref_states(const char *name,
704822struct show_info {
705823 struct string_list * list ;
706824 struct ref_states * states ;
707- int width ;
825+ int width , width2 ;
708826 int any_rebase ;
709827};
710828
@@ -799,6 +917,58 @@ int show_local_info_item(struct string_list_item *item, void *cb_data)
799917 return 0 ;
800918}
801919
920+ int add_push_to_show_info (struct string_list_item * push_item , void * cb_data )
921+ {
922+ struct show_info * show_info = cb_data ;
923+ struct push_info * push_info = push_item -> util ;
924+ struct string_list_item * item ;
925+ int n ;
926+ if ((n = strlen (push_item -> string )) > show_info -> width )
927+ show_info -> width = n ;
928+ if ((n = strlen (push_info -> dest )) > show_info -> width2 )
929+ show_info -> width2 = n ;
930+ item = string_list_append (push_item -> string , show_info -> list );
931+ item -> util = push_item -> util ;
932+ return 0 ;
933+ }
934+
935+ int show_push_info_item (struct string_list_item * item , void * cb_data )
936+ {
937+ struct show_info * show_info = cb_data ;
938+ struct push_info * push_info = item -> util ;
939+ char * src = item -> string , * status = NULL ;
940+
941+ switch (push_info -> status ) {
942+ case PUSH_STATUS_CREATE :
943+ status = "create" ;
944+ break ;
945+ case PUSH_STATUS_DELETE :
946+ status = "delete" ;
947+ src = "(none)" ;
948+ break ;
949+ case PUSH_STATUS_UPTODATE :
950+ status = "up to date" ;
951+ break ;
952+ case PUSH_STATUS_FASTFORWARD :
953+ status = "fast forwardable" ;
954+ break ;
955+ case PUSH_STATUS_OUTOFDATE :
956+ status = "local out of date" ;
957+ break ;
958+ case PUSH_STATUS_NOTQUERIED :
959+ break ;
960+ }
961+ if (status )
962+ printf (" %-*s %s to %-*s (%s)\n" , show_info -> width , src ,
963+ push_info -> forced ? "forces" : "pushes" ,
964+ show_info -> width2 , push_info -> dest , status );
965+ else
966+ printf (" %-*s %s to %s\n" , show_info -> width , src ,
967+ push_info -> forced ? "forces" : "pushes" ,
968+ push_info -> dest );
969+ return 0 ;
970+ }
971+
802972static int show (int argc , const char * * argv )
803973{
804974 int no_query = 0 , result = 0 , query_flag = 0 ;
@@ -817,7 +987,7 @@ static int show(int argc, const char **argv)
817987 return show_all ();
818988
819989 if (!no_query )
820- query_flag = (GET_REF_STATES | GET_HEAD_NAMES );
990+ query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES );
821991
822992 memset (& states , 0 , sizeof (states ));
823993 memset (& info , 0 , sizeof (info ));
@@ -867,19 +1037,18 @@ static int show(int argc, const char **argv)
8671037 string_list_clear (info .list , 0 );
8681038
8691039 /* git push info */
870- if (states .remote -> push_refspec_nr ) {
871- printf (" Local branch%s pushed with 'git push'\n" ,
872- states .remote -> push_refspec_nr > 1 ?
873- "es" : "" );
874- for (i = 0 ; i < states .remote -> push_refspec_nr ; i ++ ) {
875- struct refspec * spec = states .remote -> push + i ;
876- printf (" %s%s%s%s\n" ,
877- spec -> force ? "+" : "" ,
878- abbrev_branch (spec -> src ),
879- spec -> dst ? ":" : "" ,
880- spec -> dst ? abbrev_branch (spec -> dst ) : "" );
881- }
882- }
1040+ if (states .remote -> mirror )
1041+ printf (" Local refs will be mirrored by 'git push'\n" );
1042+
1043+ info .width = info .width2 = 0 ;
1044+ for_each_string_list (add_push_to_show_info , & states .push , & info );
1045+ sort_string_list (info .list );
1046+ if (info .list -> nr )
1047+ printf (" Local ref%s configured for 'git push'%s:\n" ,
1048+ info .list -> nr > 1 ? "s" : "" ,
1049+ no_query ? " (status not queried)" : "" );
1050+ for_each_string_list (show_push_info_item , info .list , & info );
1051+ string_list_clear (info .list , 0 );
8831052
8841053 free_remote_ref_states (& states );
8851054 }
0 commit comments