2929
3030enum map_direction { FROM_SRC , FROM_DST };
3131
32+ enum {
33+ ENABLE_ADVICE_PULL = (1 << 0 ),
34+ ENABLE_ADVICE_PUSH = (1 << 1 ),
35+ ENABLE_ADVICE_DIVERGENCE = (1 << 2 ),
36+ };
37+
3238struct counted_string {
3339 size_t len ;
3440 const char * s ;
@@ -2241,13 +2247,53 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
22412247 return stat_branch_pair (branch -> refname , base , num_ours , num_theirs , abf );
22422248}
22432249
2250+ static char * resolve_compare_branch (struct branch * branch , const char * name )
2251+ {
2252+ struct strbuf buf = STRBUF_INIT ;
2253+ const char * resolved = NULL ;
2254+ char * ret ;
2255+
2256+ if (!branch || !name )
2257+ return NULL ;
2258+
2259+ if (!strcasecmp (name , "@{upstream}" ) || !strcasecmp (name , "@{u}" ))
2260+ resolved = branch_get_upstream (branch , NULL );
2261+ else if (!strcasecmp (name , "@{push}" ))
2262+ resolved = branch_get_push (branch , NULL );
2263+
2264+ if (resolved )
2265+ return xstrdup (resolved );
2266+
2267+ strbuf_addf (& buf , "refs/remotes/%s" , name );
2268+ resolved = refs_resolve_ref_unsafe (
2269+ get_main_ref_store (the_repository ),
2270+ buf .buf ,
2271+ RESOLVE_REF_READING ,
2272+ NULL , NULL );
2273+ if (resolved ) {
2274+ ret = xstrdup (resolved );
2275+ strbuf_release (& buf );
2276+ return ret ;
2277+ }
2278+
2279+ strbuf_release (& buf );
2280+ return NULL ;
2281+ }
2282+
22442283static void format_branch_comparison (struct strbuf * sb ,
22452284 bool up_to_date ,
22462285 int ours , int theirs ,
22472286 const char * branch_name ,
22482287 enum ahead_behind_flags abf ,
2249- bool show_divergence_advice )
2288+ unsigned flags )
22502289{
2290+ bool enable_push_advice = (flags & ENABLE_ADVICE_PUSH ) &&
2291+ advice_enabled (ADVICE_STATUS_HINTS );
2292+ bool enable_pull_advice = (flags & ENABLE_ADVICE_PULL ) &&
2293+ advice_enabled (ADVICE_STATUS_HINTS );
2294+ bool enable_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE ) &&
2295+ advice_enabled (ADVICE_STATUS_HINTS );
2296+
22512297 if (up_to_date ) {
22522298 strbuf_addf (sb ,
22532299 _ ("Your branch is up to date with '%s'.\n" ),
@@ -2256,7 +2302,7 @@ static void format_branch_comparison(struct strbuf *sb,
22562302 strbuf_addf (sb ,
22572303 _ ("Your branch and '%s' refer to different commits.\n" ),
22582304 branch_name );
2259- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2305+ if (enable_push_advice )
22602306 strbuf_addf (sb , _ (" (use \"%s\" for details)\n" ),
22612307 "git status --ahead-behind" );
22622308 } else if (!theirs ) {
@@ -2265,7 +2311,7 @@ static void format_branch_comparison(struct strbuf *sb,
22652311 "Your branch is ahead of '%s' by %d commits.\n" ,
22662312 ours ),
22672313 branch_name , ours );
2268- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2314+ if (enable_push_advice )
22692315 strbuf_addstr (sb ,
22702316 _ (" (use \"git push\" to publish your local commits)\n" ));
22712317 } else if (!ours ) {
@@ -2276,7 +2322,7 @@ static void format_branch_comparison(struct strbuf *sb,
22762322 "and can be fast-forwarded.\n" ,
22772323 theirs ),
22782324 branch_name , theirs );
2279- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2325+ if (enable_pull_advice )
22802326 strbuf_addstr (sb ,
22812327 _ (" (use \"git pull\" to update your local branch)\n" ));
22822328 } else {
@@ -2289,8 +2335,7 @@ static void format_branch_comparison(struct strbuf *sb,
22892335 "respectively.\n" ,
22902336 ours + theirs ),
22912337 branch_name , ours , theirs );
2292- if (show_divergence_advice &&
2293- advice_enabled (ADVICE_STATUS_HINTS ))
2338+ if (enable_divergence_advice )
22942339 strbuf_addstr (sb ,
22952340 _ (" (use \"git pull\" if you want to integrate the remote branch with yours)\n" ));
22962341 }
@@ -2303,34 +2348,87 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
23032348 enum ahead_behind_flags abf ,
23042349 int show_divergence_advice )
23052350{
2306- int ours , theirs , cmp_fetch ;
2307- const char * full_base ;
2308- char * base ;
2309- int upstream_is_gone = 0 ;
2310-
2311- cmp_fetch = stat_tracking_info (branch , & ours , & theirs , & full_base , 0 , abf );
2312- if (cmp_fetch < 0 ) {
2313- if (!full_base )
2314- return 0 ;
2315- upstream_is_gone = 1 ;
2351+ char * compare_branches_config = NULL ;
2352+ struct string_list compare_branches = STRING_LIST_INIT_DUP ;
2353+ struct string_list_item * item ;
2354+ int reported = 0 ;
2355+ size_t i ;
2356+ const char * upstream_ref ;
2357+ const char * push_ref ;
2358+
2359+ repo_config_get_string (the_repository , "status.comparebranches" ,
2360+ & compare_branches_config );
2361+
2362+ if (compare_branches_config ) {
2363+ string_list_split (& compare_branches , compare_branches_config ,
2364+ " " , -1 );
2365+ string_list_remove_empty_items (& compare_branches , 0 );
2366+ } else {
2367+ string_list_append (& compare_branches , "@{upstream}" );
23162368 }
23172369
2318- base = refs_shorten_unambiguous_ref ( get_main_ref_store ( the_repository ),
2319- full_base , 0 );
2370+ upstream_ref = branch_get_upstream ( branch , NULL );
2371+ push_ref = branch_get_push ( branch , NULL );
23202372
2321- if (upstream_is_gone ) {
2322- strbuf_addf (sb ,
2323- _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2324- base );
2325- if (advice_enabled (ADVICE_STATUS_HINTS ))
2326- strbuf_addstr (sb ,
2327- _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2328- } else {
2329- format_branch_comparison (sb , !cmp_fetch , ours , theirs , base , abf , show_divergence_advice );
2373+ for (i = 0 ; i < compare_branches .nr ; i ++ ) {
2374+ char * full_ref ;
2375+ char * short_ref ;
2376+ int ours , theirs , cmp ;
2377+ int is_upstream , is_push ;
2378+ unsigned flags = 0 ;
2379+
2380+ item = & compare_branches .items [i ];
2381+ full_ref = resolve_compare_branch (branch , item -> string );
2382+ if (!full_ref )
2383+ continue ;
2384+
2385+ short_ref = refs_shorten_unambiguous_ref (
2386+ get_main_ref_store (the_repository ), full_ref , 0 );
2387+
2388+ is_upstream = upstream_ref && !strcmp (full_ref , upstream_ref );
2389+ is_push = push_ref && !strcmp (full_ref , push_ref );
2390+
2391+ if (is_upstream && (!push_ref || !strcmp (upstream_ref , push_ref )))
2392+ is_push = 1 ;
2393+
2394+ cmp = stat_branch_pair (branch -> refname , full_ref ,
2395+ & ours , & theirs , abf );
2396+
2397+ if (cmp < 0 ) {
2398+ if (is_upstream ) {
2399+ strbuf_addf (sb ,
2400+ _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2401+ short_ref );
2402+ if (advice_enabled (ADVICE_STATUS_HINTS ))
2403+ strbuf_addstr (sb ,
2404+ _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2405+ reported = 1 ;
2406+ }
2407+ free (full_ref );
2408+ free (short_ref );
2409+ continue ;
2410+ }
2411+
2412+ if (reported )
2413+ strbuf_addstr (sb , "\n" );
2414+
2415+ if (is_upstream )
2416+ flags |= ENABLE_ADVICE_PULL ;
2417+ if (is_push )
2418+ flags |= ENABLE_ADVICE_PUSH ;
2419+ if (show_divergence_advice && is_upstream )
2420+ flags |= ENABLE_ADVICE_DIVERGENCE ;
2421+ format_branch_comparison (sb , !cmp , ours , theirs , short_ref ,
2422+ abf , flags );
2423+ reported = 1 ;
2424+
2425+ free (full_ref );
2426+ free (short_ref );
23302427 }
23312428
2332- free (base );
2333- return 1 ;
2429+ string_list_clear (& compare_branches , 0 );
2430+ free (compare_branches_config );
2431+ return reported ;
23342432}
23352433
23362434static int one_local_ref (const struct reference * ref , void * cb_data )
0 commit comments