Subject: [PATCH v2 0/2] status: show default branch comparison when tracking non-default branch

From: "Harald Nordgren via GitGitGadget" <[email-masked]>
Date: Tue, 23 Dec 2025 22:54:06 +0000

cc: Chris Torek [email-masked]

Harald Nordgren (2):
  status: show comparison with upstream default branch
  Simplify default branch comparison logic

 remote.c                 |  83 +++++++++++++
 t/t6040-tracking-info.sh | 246 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 329 insertions(+)

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

Range-diff vs v1:

 1:  c27a806dc9 ! 1:  a3800aed18 status: show default branch comparison when tracking non-default branch
     @@ Metadata
      Author: Harald Nordgren <[email-masked]>
      
       ## Commit message ##
     -    status: show default branch comparison when tracking non-default branch
     +    status: show comparison with upstream default branch
      
     -    When a branch tracks a non-default remote branch (e.g.,
     -    origin/feature), git status now also displays how the branch
     -    compares to the default branch (origin/main or upstream/main).
     -    This helps users understand if their branch has drifted from the
     -    main development line even when it's in sync with its tracking
     -    branch.
     +    "git status" on a branch that follows a remote branch compares
     +    commits on the current branch and the remote-tracking branch it
     +    builds upon, to show "ahead" (i.e. you have built new history,
     +    while others are not touching it), "behind" (i.e. you haven't
     +    added any work since you were in-sync, while others have added
     +    their work on the branch), "diverged" (i.e. you have commits
     +    that you haven't pushed out, while others have added commits).
      
     -    The comparison is shown as a separate line after the tracking
     -    branch status:
     +    When you fork a branch 'feature' from the 'main' branch of the
     +    remote, but then create 'feature' branch at the remote and push
     +    there, while you still occasionally pull from or rebase onto
     +    their 'main', you'd also want to know how much you have diverged
     +    from 'main', in addition to how your 'feature' and their
     +    'feature' compares. Currently the comparison with 'main' is not
     +    given, making it hard to know when to start thinking about
     +    rebasing onto the upstream default branch.
     +
     +    Show two sets of comparison: one with the tracking branch (as
     +    before), and another with the upstream's default branch (what
     +    their HEAD points to, typically 'main' or 'master'). The latter
     +    comparison appears on a separate line after the tracking branch
     +    status, using the same format:
          - "Ahead of 'origin/main' by N commits" when purely ahead
          - "Behind 'origin/main' by N commits" when purely behind
          - "Diverged from 'origin/main' by N commits" when diverged
      
          Example output when tracking a feature branch:
     -
              On branch feature
              Your branch is ahead of 'origin/feature' by 2 commits.
                (use "git push" to publish your local commits)
      
              Ahead of 'origin/main' by 5 commits.
      
     -    The default branch is determined dynamically by checking:
     +    The upstream default branch is determined by checking symbolic refs:
          1. refs/remotes/upstream/HEAD (if upstream remote exists)
          2. refs/remotes/origin/HEAD (fallback)
      
          This works with any default branch name (main, master, develop,
          etc.) as long as the symbolic ref is configured. The comparison
          is also shown when the branch is up-to-date with its tracking
     -    branch but differs from the default branch.
     +    branch but differs from the upstream default branch.
      
          Signed-off-by: Harald Nordgren <[email-masked]>
      
     @@ 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 const char *get_default_remote_ref(char **full_ref_out)
     ++static char *get_default_remote_ref(char **full_ref_out)
      +{
      +	int flag;
      +	const char *resolved;
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +static int is_default_remote_branch(const char *name)
      +{
      +	char *default_full = NULL;
     -+	const char *default_short;
     ++	char *default_short;
      +	int result = 0;
      +
      +	default_short = get_default_remote_ref(&default_full);
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +
      +	result = !strcmp(name, default_short);
      +
     ++	free(default_short);
      +	free(default_full);
      +	return result;
      +}
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +{
      +	int default_ours = 0, default_theirs = 0;
      +	char *default_full = NULL;
     -+	const char *default_short;
     ++	char *default_short;
      +
      +	default_short = get_default_remote_ref(&default_full);
      +	if (!default_short)
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +
      +	if (stat_branch_pair(branch_refname, default_full,
      +			     &default_ours, &default_theirs, abf) <= 0) {
     ++		free(default_short);
      +		free(default_full);
      +		return;
      +	}
     @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_
      +			default_short, default_ours + default_theirs);
      +	}
      +
     ++	free(default_short);
      +	free(default_full);
      +}
      +
 -:  ---------- > 2:  417f2075fb Simplify default branch comparison logic

-- 
gitgitgadget