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,40 @@ 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+ const char * resolved = NULL ;
2253+
2254+ if (!branch || !name )
2255+ return NULL ;
2256+
2257+ if (!strcasecmp (name , "@{upstream}" )) {
2258+ resolved = branch_get_upstream (branch , NULL );
2259+ } else if (!strcasecmp (name , "@{push}" )) {
2260+ resolved = branch_get_push (branch , NULL );
2261+ } else {
2262+ warning (_ ("ignoring value '%s' for status.compareBranches, "
2263+ "only @{upstream} and @{push} are supported" ),
2264+ name );
2265+ return NULL ;
2266+ }
2267+
2268+ if (resolved )
2269+ return xstrdup (resolved );
2270+ return NULL ;
2271+ }
2272+
22442273static void format_branch_comparison (struct strbuf * sb ,
22452274 bool up_to_date ,
22462275 int ours , int theirs ,
22472276 const char * branch_name ,
22482277 enum ahead_behind_flags abf ,
2249- bool show_divergence_advice )
2278+ unsigned flags )
22502279{
2280+ bool use_push_advice = (flags & ENABLE_ADVICE_PUSH );
2281+ bool use_pull_advice = (flags & ENABLE_ADVICE_PULL );
2282+ bool use_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE );
2283+
22512284 if (up_to_date ) {
22522285 strbuf_addf (sb ,
22532286 _ ("Your branch is up to date with '%s'.\n" ),
@@ -2256,7 +2289,7 @@ static void format_branch_comparison(struct strbuf *sb,
22562289 strbuf_addf (sb ,
22572290 _ ("Your branch and '%s' refer to different commits.\n" ),
22582291 branch_name );
2259- if (advice_enabled (ADVICE_STATUS_HINTS ))
2292+ if (use_push_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22602293 strbuf_addf (sb , _ (" (use \"%s\" for details)\n" ),
22612294 "git status --ahead-behind" );
22622295 } else if (!theirs ) {
@@ -2265,7 +2298,7 @@ static void format_branch_comparison(struct strbuf *sb,
22652298 "Your branch is ahead of '%s' by %d commits.\n" ,
22662299 ours ),
22672300 branch_name , ours );
2268- if (advice_enabled (ADVICE_STATUS_HINTS ))
2301+ if (use_push_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22692302 strbuf_addstr (sb ,
22702303 _ (" (use \"git push\" to publish your local commits)\n" ));
22712304 } else if (!ours ) {
@@ -2276,7 +2309,7 @@ static void format_branch_comparison(struct strbuf *sb,
22762309 "and can be fast-forwarded.\n" ,
22772310 theirs ),
22782311 branch_name , theirs );
2279- if (advice_enabled (ADVICE_STATUS_HINTS ))
2312+ if (use_pull_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22802313 strbuf_addstr (sb ,
22812314 _ (" (use \"git pull\" to update your local branch)\n" ));
22822315 } else {
@@ -2289,8 +2322,7 @@ static void format_branch_comparison(struct strbuf *sb,
22892322 "respectively.\n" ,
22902323 ours + theirs ),
22912324 branch_name , ours , theirs );
2292- if (show_divergence_advice &&
2293- advice_enabled (ADVICE_STATUS_HINTS ))
2325+ if (use_divergence_advice && advice_enabled (ADVICE_STATUS_HINTS ))
22942326 strbuf_addstr (sb ,
22952327 _ (" (use \"git pull\" if you want to integrate the remote branch with yours)\n" ));
22962328 }
@@ -2303,34 +2335,92 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
23032335 enum ahead_behind_flags abf ,
23042336 int show_divergence_advice )
23052337{
2306- int ours , theirs , cmp_fetch ;
2307- const char * full_base ;
2308- char * base ;
2309- int upstream_is_gone = 0 ;
2338+ char * compare_branches = NULL ;
2339+ struct string_list branches = STRING_LIST_INIT_DUP ;
2340+ struct strset processed_refs = STRSET_INIT ;
2341+ int reported = 0 ;
2342+ size_t i ;
2343+ const char * upstream_ref ;
2344+ const char * push_ref ;
23102345
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 ;
2346+ repo_config_get_string (the_repository , "status.comparebranches" ,
2347+ & compare_branches );
2348+
2349+ if (compare_branches ) {
2350+ string_list_split (& branches , compare_branches , " " , -1 );
2351+ string_list_remove_empty_items (& branches , 0 );
2352+ } else {
2353+ string_list_append (& branches , "@{upstream}" );
23162354 }
23172355
2318- base = refs_shorten_unambiguous_ref ( get_main_ref_store ( the_repository ),
2319- full_base , 0 );
2356+ upstream_ref = branch_get_upstream ( branch , NULL );
2357+ push_ref = branch_get_push ( branch , NULL );
23202358
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 );
2359+ for (i = 0 ; i < branches .nr ; i ++ ) {
2360+ char * full_ref ;
2361+ char * short_ref ;
2362+ int ours , theirs , cmp ;
2363+ int is_upstream , is_push ;
2364+ unsigned flags = 0 ;
2365+
2366+ full_ref = resolve_compare_branch (branch ,
2367+ branches .items [i ].string );
2368+ if (!full_ref )
2369+ continue ;
2370+
2371+ if (!strset_add (& processed_refs , full_ref )) {
2372+ free (full_ref );
2373+ continue ;
2374+ }
2375+
2376+ short_ref = refs_shorten_unambiguous_ref (
2377+ get_main_ref_store (the_repository ), full_ref , 0 );
2378+
2379+ is_upstream = upstream_ref && !strcmp (full_ref , upstream_ref );
2380+ is_push = push_ref && !strcmp (full_ref , push_ref );
2381+
2382+ if (is_upstream && (!push_ref || !strcmp (upstream_ref , push_ref )))
2383+ is_push = 1 ;
2384+
2385+ cmp = stat_branch_pair (branch -> refname , full_ref ,
2386+ & ours , & theirs , abf );
2387+
2388+ if (cmp < 0 ) {
2389+ if (is_upstream ) {
2390+ strbuf_addf (sb ,
2391+ _ ("Your branch is based on '%s', but the upstream is gone.\n" ),
2392+ short_ref );
2393+ if (advice_enabled (ADVICE_STATUS_HINTS ))
2394+ strbuf_addstr (sb ,
2395+ _ (" (use \"git branch --unset-upstream\" to fixup)\n" ));
2396+ reported = 1 ;
2397+ }
2398+ free (full_ref );
2399+ free (short_ref );
2400+ continue ;
2401+ }
2402+
2403+ if (reported )
2404+ strbuf_addstr (sb , "\n" );
2405+
2406+ if (is_upstream )
2407+ flags |= ENABLE_ADVICE_PULL ;
2408+ if (is_push )
2409+ flags |= ENABLE_ADVICE_PUSH ;
2410+ if (show_divergence_advice && is_upstream )
2411+ flags |= ENABLE_ADVICE_DIVERGENCE ;
2412+ format_branch_comparison (sb , !cmp , ours , theirs , short_ref ,
2413+ abf , flags );
2414+ reported = 1 ;
2415+
2416+ free (full_ref );
2417+ free (short_ref );
23302418 }
23312419
2332- free (base );
2333- return 1 ;
2420+ string_list_clear (& branches , 0 );
2421+ strset_clear (& processed_refs );
2422+ free (compare_branches );
2423+ return reported ;
23342424}
23352425
23362426static int one_local_ref (const struct reference * ref , void * cb_data )
0 commit comments