Subject: [PATCH v24 0/2] status: show comparison with push remote tracking branch

From: "Harald Nordgren via GitGitGadget" <[email-masked]>
Date: Tue, 13 Jan 2026 09:55:16 +0000

cc: Chris Torek [email-masked] cc: Yee Cheng Chin
[email-masked] cc: "brian m. carlson" [email-masked]
cc: Ben Knoble [email-masked] cc: "Kristoffer Haugsbakk"
[email-masked] cc: Phillip Wood [email-masked]
cc: Nico Williams [email-masked] cc: Patrick Steinhardt [email-masked]

Harald Nordgren (2):
  refactor format_branch_comparison in preparation
  status: show comparison with push remote tracking branch

 remote.c                 | 175 ++++++++++++++++++++------
 t/t6040-tracking-info.sh | 262 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 402 insertions(+), 35 deletions(-)

base-commit: 8745eae506f700657882b9e32b2aa00f234a6fb6
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2138%2FHaraldNordgren%2Fahead_of_main_status-v24
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2138/HaraldNordgren/ahead_of_main_status-v24
Pull-Request: https://github.com/git/git/pull/2138

Range-diff vs v23:

 1:  fd05c7b778 = 1:  fd05c7b778 refactor format_branch_comparison in preparation
 2:  f1ad7a1b6f ! 2:  138b79a0b9 status: show comparison with push remote tracking branch
     @@ remote.c
       enum map_direction { FROM_SRC, FROM_DST };
       
      +enum {
     -+	BRANCH_MODE_PULL = (1 << 0),
     -+	BRANCH_MODE_PUSH = (1 << 1),
     ++	ENABLE_ADVICE_PULL       = (1 << 0),
     ++	ENABLE_ADVICE_PUSH       = (1 << 1),
     ++	ENABLE_ADVICE_DIVERGENCE = (1 << 2),
      +};
      +
       struct counted_string {
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
       	return stat_branch_pair(branch->refname, base, num_ours, num_theirs, abf);
       }
       
     -+static char *get_remote_push_branch(struct branch *branch, char **full_ref_out)
     ++static char *get_remote_push_branch(struct branch *branch)
      +{
      +	struct remote *remote;
      +	const char *push_remote;
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +		return NULL;
      +	}
      +
     -+	if (full_ref_out)
     -+		*full_ref_out = xstrdup(resolved);
     -+
     -+	ret = refs_shorten_unambiguous_ref(
     -+		get_main_ref_store(the_repository), resolved, 0);
     ++	ret = xstrdup(resolved);
      +	free(tracking_ref);
      +	return ret;
      +}
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
       				     int ours, int theirs,
       				     const char *branch_name,
       				     enum ahead_behind_flags abf,
     -+				     unsigned flags,
     - 				     bool show_divergence_advice)
     +-				     bool show_divergence_advice)
     ++				     unsigned flags)
       {
     -+	bool want_push_advice = (flags & BRANCH_MODE_PUSH) &&
     ++	bool enable_push_advice = (flags & ENABLE_ADVICE_PUSH) &&
      +		advice_enabled(ADVICE_STATUS_HINTS);
     -+	bool want_pull_advice = (flags & BRANCH_MODE_PULL) &&
     ++	bool enable_pull_advice = (flags & ENABLE_ADVICE_PULL) &&
      +		advice_enabled(ADVICE_STATUS_HINTS);
     -+	bool want_divergence_advice = show_divergence_advice &&
     ++	bool enable_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE) &&
      +		advice_enabled(ADVICE_STATUS_HINTS);
      +
       	if (up_to_date) {
     @@ remote.c: static void format_branch_comparison(struct strbuf *sb,
       			    _("Your branch and '%s' refer to different commits.\n"),
       			    branch_name);
      -		if (advice_enabled(ADVICE_STATUS_HINTS))
     -+		if (want_push_advice)
     ++		if (enable_push_advice)
       			strbuf_addf(sb, _("  (use \"%s\" for details)\n"),
       				    "git status --ahead-behind");
       	} else if (!theirs) {
     @@ remote.c: static void format_branch_comparison(struct strbuf *sb,
       			   ours),
       			branch_name, ours);
      -		if (advice_enabled(ADVICE_STATUS_HINTS))
     -+		if (want_push_advice)
     ++		if (enable_push_advice)
       			strbuf_addstr(sb,
       				_("  (use \"git push\" to publish your local commits)\n"));
       	} else if (!ours) {
     @@ remote.c: static void format_branch_comparison(struct strbuf *sb,
       			   theirs),
       			branch_name, theirs);
      -		if (advice_enabled(ADVICE_STATUS_HINTS))
     -+		if (want_pull_advice)
     ++		if (enable_pull_advice)
       			strbuf_addstr(sb,
       				_("  (use \"git pull\" to update your local branch)\n"));
       	} else {
     @@ remote.c: static void format_branch_comparison(struct strbuf *sb,
       			branch_name, ours, theirs);
      -		if (show_divergence_advice &&
      -		    advice_enabled(ADVICE_STATUS_HINTS))
     -+		if (want_divergence_advice)
     ++		if (enable_divergence_advice)
       			strbuf_addstr(sb,
       				_("  (use \"git pull\" if you want to integrate the remote branch with yours)\n"));
       	}
     @@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
       	const char *full_base;
       	char *base;
       	int upstream_is_gone = 0;
     -+	unsigned base_branch_modes = BRANCH_MODE_PULL | BRANCH_MODE_PUSH;
     ++	unsigned base_branch_flags = ENABLE_ADVICE_PULL | ENABLE_ADVICE_PUSH;
      +	int push_ours, push_theirs, push_cmp_fetch;
     -+	char *full_push = NULL;
     ++	char *full_push;
      +	char *push = NULL;
     -+	unsigned push_branch_modes = 0;
     ++	unsigned push_branch_flags = 0;
       
       	cmp_fetch = stat_tracking_info(branch, &ours, &theirs, &full_base, 0, abf);
       	if (cmp_fetch < 0) {
     @@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
       	base = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
       					    full_base, 0);
       
     -+	push = get_remote_push_branch(branch, &full_push);
     -+	if (push && strcmp(base, push)) {
     -+		push_cmp_fetch = stat_branch_pair(branch->refname, full_push,
     -+					   &push_ours, &push_theirs, abf);
     -+		if (push_cmp_fetch >= 0) {
     -+			base_branch_modes = BRANCH_MODE_PULL;
     -+			push_branch_modes = BRANCH_MODE_PUSH;
     ++	full_push = get_remote_push_branch(branch);
     ++	if (full_push) {
     ++		push = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
     ++						     full_push, 0);
     ++		if (push && base && strcmp(base, push)) {
     ++			push_cmp_fetch = stat_branch_pair(branch->refname, full_push,
     ++						   &push_ours, &push_theirs, abf);
     ++			if (push_cmp_fetch >= 0) {
     ++				base_branch_flags = ENABLE_ADVICE_PULL;
     ++				push_branch_flags = ENABLE_ADVICE_PUSH;
     ++			}
      +		}
      +	}
      +
     @@ remote.c: int format_tracking_info(struct branch *branch, struct strbuf *sb,
       				_("  (use \"git branch --unset-upstream\" to fixup)\n"));
       	} else {
      -		format_branch_comparison(sb, !cmp_fetch, ours, theirs, base, abf, show_divergence_advice);
     ++		if (show_divergence_advice)
     ++			base_branch_flags |= ENABLE_ADVICE_DIVERGENCE;
      +		format_branch_comparison(sb, !cmp_fetch, ours, theirs, base, abf,
     -+					 base_branch_modes, show_divergence_advice);
     ++					 base_branch_flags);
      +	}
      +
     -+	if (push_branch_modes & BRANCH_MODE_PUSH) {
     ++	if (push_branch_flags & ENABLE_ADVICE_PUSH) {
      +		strbuf_addstr(sb, "\n");
      +		format_branch_comparison(sb, !push_cmp_fetch, push_ours, push_theirs, push, abf,
     -+					 push_branch_modes, 0);
     ++					 push_branch_flags);
       	}
       
       	free(base);

-- 
gitgitgadget