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 ;
@@ -2234,13 +2240,42 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
22342240 return stat_branch_pair (branch -> refname , base , num_ours , num_theirs , abf );
22352241}
22362242
2243+ static char * resolve_compare_branch (struct branch * branch , const char * name )
2244+ {
2245+ const char * resolved = NULL ;
2246+
2247+ if (!branch || !name )
2248+ return NULL ;
2249+
2250+ if (!strcasecmp (name , "@{upstream}" ))
2251+ resolved = branch_get_upstream (branch , NULL );
2252+ else if (!strcasecmp (name , "@{push}" ))
2253+ resolved = branch_get_push (branch , NULL );
2254+ else {
2255+ warning (_ ("ignoring value '%s' for status.compareBranches; only @{upstream} and @{push} are supported" ),
2256+ name );
2257+ return NULL ;
2258+ }
2259+
2260+ if (resolved )
2261+ return xstrdup (resolved );
2262+ return NULL ;
2263+ }
2264+
22372265static void format_branch_comparison (struct strbuf * sb ,
22382266 bool up_to_date ,
22392267 int ours , int theirs ,
22402268 const char * branch_name ,
22412269 enum ahead_behind_flags abf ,
2242- bool show_divergence_advice )
2270+ unsigned flags )
22432271{
2272+ bool enable_push_advice = (flags & ENABLE_ADVICE_PUSH ) &&
2273+ advice_enabled (ADVICE_STATUS_HINTS );
2274+ bool enable_pull_advice = (flags & ENABLE_ADVICE_PULL ) &&
2275+ advice_enabled (ADVICE_STATUS_HINTS );
2276+ bool enable_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE ) &&
2277+ advice_enabled (ADVICE_STATUS_HINTS );
2278+
22442279 if (up_to_date ) {
22452280 strbuf_addf (sb ,
22462281 _ ("Your branch is up to date with '%s'.\n" ),
@@ -2249,7 +2284,7 @@ static void format_branch_comparison(struct strbuf *sb,
22492284 strbuf_addf (sb ,
22502285 _ ("Your branch and '%s' refer to different commits.\n" ),
22512286 branch_name );
2252- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2287+ if (enable_push_advice )
22532288 strbuf_addf (sb , _ (" (use \"%s\" for details)\n" ),
22542289 "git status --ahead-behind" );
22552290 } else if (!theirs ) {
@@ -2258,7 +2293,7 @@ static void format_branch_comparison(struct strbuf *sb,
22582293 "Your branch is ahead of '%s' by %d commits.\n" ,
22592294 ours ),
22602295 branch_name , ours );
2261- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2296+ if (enable_push_advice )
22622297 strbuf_addstr (sb ,
22632298 _ (" (use \"git push\" to publish your local commits)\n" ));
22642299 } else if (!ours ) {
@@ -2269,7 +2304,7 @@ static void format_branch_comparison(struct strbuf *sb,
22692304 "and can be fast-forwarded.\n" ,
22702305 theirs ),
22712306 branch_name , theirs );
2272- if (advice_enabled ( ADVICE_STATUS_HINTS ) )
2307+ if (enable_pull_advice )
22732308 strbuf_addstr (sb ,
22742309 _ (" (use \"git pull\" to update your local branch)\n" ));
22752310 } else {
@@ -2282,8 +2317,7 @@ static void format_branch_comparison(struct strbuf *sb,
22822317 "respectively.\n" ,
22832318 ours + theirs ),
22842319 branch_name , ours , theirs );
2285- if (show_divergence_advice &&
2286- advice_enabled (ADVICE_STATUS_HINTS ))
2320+ if (enable_divergence_advice )
22872321 strbuf_addstr (sb ,
22882322 _ (" (use \"git pull\" if you want to integrate the remote branch with yours)\n" ));
22892323 }
@@ -2296,34 +2330,92 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
22962330 enum ahead_behind_flags abf ,
22972331 int show_divergence_advice )
22982332{
2299- int ours , theirs , cmp_fetch ;
2300- const char * full_base ;
2301- char * base ;
2302- int upstream_is_gone = 0 ;
2333+ char * compare_branches = NULL ;
2334+ struct string_list branches = STRING_LIST_INIT_DUP ;
2335+ struct strset processed_refs = STRSET_INIT ;
2336+ int reported = 0 ;
2337+ size_t i ;
2338+ const char * upstream_ref ;
2339+ const char * push_ref ;
23032340
2304- cmp_fetch = stat_tracking_info (branch , & ours , & theirs , & full_base , 0 , abf );
2305- if (cmp_fetch < 0 ) {
2306- if (!full_base )
2307- return 0 ;
2308- upstream_is_gone = 1 ;
2341+ repo_config_get_string (the_repository , "status.comparebranches" ,
2342+ & compare_branches );
2343+
2344+ if (compare_branches ) {
2345+ string_list_split (& branches , compare_branches , " " , -1 );
2346+ string_list_remove_empty_items (& branches , 0 );
2347+ } else {
2348+ string_list_append (& branches , "@{upstream}" );
23092349 }
23102350
2311- base = refs_shorten_unambiguous_ref ( get_main_ref_store ( the_repository ),
2312- full_base , 0 );
2351+ upstream_ref = branch_get_upstream ( branch , NULL );
2352+ push_ref = branch_get_push ( branch , NULL );
23132353
2314- if (upstream_is_gone ) {
2315- strbuf_addf (sb ,
2316- _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2317- base );
2318- if (advice_enabled (ADVICE_STATUS_HINTS ))
2319- strbuf_addstr (sb ,
2320- _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2321- } else {
2322- format_branch_comparison (sb , !cmp_fetch , ours , theirs , base , abf , show_divergence_advice );
2354+ for (i = 0 ; i < branches .nr ; i ++ ) {
2355+ char * full_ref ;
2356+ char * short_ref ;
2357+ int ours , theirs , cmp ;
2358+ int is_upstream , is_push ;
2359+ unsigned flags = 0 ;
2360+
2361+ full_ref = resolve_compare_branch (branch ,
2362+ branches .items [i ].string );
2363+ if (!full_ref )
2364+ continue ;
2365+
2366+ if (!strset_add (& processed_refs , full_ref )) {
2367+ free (full_ref );
2368+ continue ;
2369+ }
2370+
2371+ short_ref = refs_shorten_unambiguous_ref (
2372+ get_main_ref_store (the_repository ), full_ref , 0 );
2373+
2374+ is_upstream = upstream_ref && !strcmp (full_ref , upstream_ref );
2375+ is_push = push_ref && !strcmp (full_ref , push_ref );
2376+
2377+ if (is_upstream && (!push_ref || !strcmp (upstream_ref , push_ref )))
2378+ is_push = 1 ;
2379+
2380+ cmp = stat_branch_pair (branch -> refname , full_ref ,
2381+ & ours , & theirs , abf );
2382+
2383+ if (cmp < 0 ) {
2384+ if (is_upstream ) {
2385+ strbuf_addf (sb ,
2386+ _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2387+ short_ref );
2388+ if (advice_enabled (ADVICE_STATUS_HINTS ))
2389+ strbuf_addstr (sb ,
2390+ _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2391+ reported = 1 ;
2392+ }
2393+ free (full_ref );
2394+ free (short_ref );
2395+ continue ;
2396+ }
2397+
2398+ if (reported )
2399+ strbuf_addstr (sb , "\n" );
2400+
2401+ if (is_upstream )
2402+ flags |= ENABLE_ADVICE_PULL ;
2403+ if (is_push )
2404+ flags |= ENABLE_ADVICE_PUSH ;
2405+ if (show_divergence_advice && is_upstream )
2406+ flags |= ENABLE_ADVICE_DIVERGENCE ;
2407+ format_branch_comparison (sb , !cmp , ours , theirs , short_ref ,
2408+ abf , flags );
2409+ reported = 1 ;
2410+
2411+ free (full_ref );
2412+ free (short_ref );
23232413 }
23242414
2325- free (base );
2326- return 1 ;
2415+ string_list_clear (& branches , 0 );
2416+ strset_clear (& processed_refs );
2417+ free (compare_branches );
2418+ return reported ;
23272419}
23282420
23292421static int one_local_ref (const struct reference * ref , void * cb_data )
0 commit comments