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,40 @@ 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, "
2256+ "only @{upstream} and @{push} are supported" ),
2257+ name );
2258+ return NULL ;
2259+ }
2260+
2261+ if (resolved )
2262+ return xstrdup (resolved );
2263+ return NULL ;
2264+ }
2265+
22372266static void format_branch_comparison (struct strbuf * sb ,
22382267 bool up_to_date ,
22392268 int ours , int theirs ,
22402269 const char * branch_name ,
22412270 enum ahead_behind_flags abf ,
2242- bool show_divergence_advice )
2271+ unsigned flags )
22432272{
2273+ bool use_push_advice = (flags & ENABLE_ADVICE_PUSH );
2274+ bool use_pull_advice = (flags & ENABLE_ADVICE_PULL );
2275+ bool use_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE );
2276+
22442277 if (up_to_date ) {
22452278 strbuf_addf (sb ,
22462279 _ ("Your branch is up to date with '%s'.\n" ),
@@ -2249,7 +2282,7 @@ static void format_branch_comparison(struct strbuf *sb,
22492282 strbuf_addf (sb ,
22502283 _ ("Your branch and '%s' refer to different commits.\n" ),
22512284 branch_name );
2252- if (advice_enabled (ADVICE_STATUS_HINTS ))
2285+ if (use_push_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22532286 strbuf_addf (sb , _ (" (use \"%s\" for details)\n" ),
22542287 "git status --ahead-behind" );
22552288 } else if (!theirs ) {
@@ -2258,7 +2291,7 @@ static void format_branch_comparison(struct strbuf *sb,
22582291 "Your branch is ahead of '%s' by %d commits.\n" ,
22592292 ours ),
22602293 branch_name , ours );
2261- if (advice_enabled (ADVICE_STATUS_HINTS ))
2294+ if (use_push_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22622295 strbuf_addstr (sb ,
22632296 _ (" (use \"git push\" to publish your local commits)\n" ));
22642297 } else if (!ours ) {
@@ -2269,7 +2302,7 @@ static void format_branch_comparison(struct strbuf *sb,
22692302 "and can be fast-forwarded.\n" ,
22702303 theirs ),
22712304 branch_name , theirs );
2272- if (advice_enabled (ADVICE_STATUS_HINTS ))
2305+ if (use_pull_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22732306 strbuf_addstr (sb ,
22742307 _ (" (use \"git pull\" to update your local branch)\n" ));
22752308 } else {
@@ -2282,8 +2315,7 @@ static void format_branch_comparison(struct strbuf *sb,
22822315 "respectively.\n" ,
22832316 ours + theirs ),
22842317 branch_name , ours , theirs );
2285- if (show_divergence_advice &&
2286- advice_enabled (ADVICE_STATUS_HINTS ))
2318+ if (use_divergence_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22872319 strbuf_addstr (sb ,
22882320 _ (" (use \"git pull\" if you want to integrate the remote branch with yours)\n" ));
22892321 }
@@ -2296,34 +2328,92 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
22962328 enum ahead_behind_flags abf ,
22972329 int show_divergence_advice )
22982330{
2299- int ours , theirs , cmp_fetch ;
2300- const char * full_base ;
2301- char * base ;
2302- int upstream_is_gone = 0 ;
2331+ char * compare_branches = NULL ;
2332+ struct string_list branches = STRING_LIST_INIT_DUP ;
2333+ struct strset processed_refs = STRSET_INIT ;
2334+ int reported = 0 ;
2335+ size_t i ;
2336+ const char * upstream_ref ;
2337+ const char * push_ref ;
23032338
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 ;
2339+ repo_config_get_string (the_repository , "status.comparebranches" ,
2340+ & compare_branches );
2341+
2342+ if (compare_branches ) {
2343+ string_list_split (& branches , compare_branches , " " , -1 );
2344+ string_list_remove_empty_items (& branches , 0 );
2345+ } else {
2346+ string_list_append (& branches , "@{upstream}" );
23092347 }
23102348
2311- base = refs_shorten_unambiguous_ref ( get_main_ref_store ( the_repository ),
2312- full_base , 0 );
2349+ upstream_ref = branch_get_upstream ( branch , NULL );
2350+ push_ref = branch_get_push ( branch , NULL );
23132351
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 );
2352+ for (i = 0 ; i < branches .nr ; i ++ ) {
2353+ char * full_ref ;
2354+ char * short_ref ;
2355+ int ours , theirs , cmp ;
2356+ int is_upstream , is_push ;
2357+ unsigned flags = 0 ;
2358+
2359+ full_ref = resolve_compare_branch (branch ,
2360+ branches .items [i ].string );
2361+ if (!full_ref )
2362+ continue ;
2363+
2364+ if (!strset_add (& processed_refs , full_ref )) {
2365+ free (full_ref );
2366+ continue ;
2367+ }
2368+
2369+ short_ref = refs_shorten_unambiguous_ref (
2370+ get_main_ref_store (the_repository ), full_ref , 0 );
2371+
2372+ is_upstream = upstream_ref && !strcmp (full_ref , upstream_ref );
2373+ is_push = push_ref && !strcmp (full_ref , push_ref );
2374+
2375+ if (is_upstream && (!push_ref || !strcmp (upstream_ref , push_ref )))
2376+ is_push = 1 ;
2377+
2378+ cmp = stat_branch_pair (branch -> refname , full_ref ,
2379+ & ours , & theirs , abf );
2380+
2381+ if (cmp < 0 ) {
2382+ if (is_upstream ) {
2383+ strbuf_addf (sb ,
2384+ _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2385+ short_ref );
2386+ if (advice_enabled (ADVICE_STATUS_HINTS ))
2387+ strbuf_addstr (sb ,
2388+ _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2389+ reported = 1 ;
2390+ }
2391+ free (full_ref );
2392+ free (short_ref );
2393+ continue ;
2394+ }
2395+
2396+ if (reported )
2397+ strbuf_addstr (sb , "\n" );
2398+
2399+ if (is_upstream )
2400+ flags |= ENABLE_ADVICE_PULL ;
2401+ if (is_push )
2402+ flags |= ENABLE_ADVICE_PUSH ;
2403+ if (show_divergence_advice && is_upstream )
2404+ flags |= ENABLE_ADVICE_DIVERGENCE ;
2405+ format_branch_comparison (sb , !cmp , ours , theirs , short_ref ,
2406+ abf , flags );
2407+ reported = 1 ;
2408+
2409+ free (full_ref );
2410+ free (short_ref );
23232411 }
23242412
2325- free (base );
2326- return 1 ;
2413+ string_list_clear (& branches , 0 );
2414+ strset_clear (& processed_refs );
2415+ free (compare_branches );
2416+ return reported ;
23272417}
23282418
23292419static int one_local_ref (const struct reference * ref , void * cb_data )
0 commit comments