From: Harald Nordgren via GitGitGadget Date: Thu, 26 Feb 2026 10:33:40 GMT Subject: [PATCH v30 0/2] status: add status.compareBranches config for multiple branch comparisons Message-ID: In-Reply-To: cc: Chris Torek chris.torek@gmail.com cc: Yee Cheng Chin ychin.macvim@gmail.com cc: "brian m. carlson" sandals@crustytoothpaste.net cc: Ben Knoble ben.knoble@gmail.com cc: "Kristoffer Haugsbakk" kristofferhaugsbakk@fastmail.com cc: Phillip Wood phillip.wood123@gmail.com cc: Nico Williams nico@cryptonector.com cc: Patrick Steinhardt ps@pks.im cc: Jeff King peff@peff.net Harald Nordgren (2): refactor format_branch_comparison in preparation status: add status.compareBranches config for multiple branch comparisons Documentation/config/status.adoc | 19 ++ remote.c | 178 ++++++++++++++---- t/t6040-tracking-info.sh | 310 +++++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+), 37 deletions(-) base-commit: 7b2bccb0d58d4f24705bf985de1f4612e4cf06e5 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2138%2FHaraldNordgren%2Fahead_of_main_status-v30 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2138/HaraldNordgren/ahead_of_main_status-v30 Pull-Request: https://github.com/git/git/pull/2138 Range-diff vs v29: 1: 48db1f4847 = 1: 7f517b8c7f refactor format_branch_comparison in preparation 2: 6a88f41fa5 ! 2: 501bd40294 status: add status.compareBranches config for multiple branch comparisons @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_ + if (!branch || !name) + return NULL; + -+ if (!strcasecmp(name, "@{upstream}")) ++ if (!strcasecmp(name, "@{upstream}")) { + resolved = branch_get_upstream(branch, NULL); -+ else if (!strcasecmp(name, "@{push}")) ++ } else if (!strcasecmp(name, "@{push}")) { + resolved = branch_get_push(branch, NULL); -+ else { -+ warning(_("ignoring value '%s' for status.compareBranches; only @{upstream} and @{push} are supported"), ++ } else { ++ warning(_("ignoring value '%s' for status.compareBranches, " ++ "only @{upstream} and @{push} are supported"), + name); + return NULL; + } @@ remote.c: int stat_tracking_info(struct branch *branch, int *num_ours, int *num_ - bool show_divergence_advice) + unsigned flags) { -+ bool enable_push_advice = (flags & ENABLE_ADVICE_PUSH) && -+ advice_enabled(ADVICE_STATUS_HINTS); -+ bool enable_pull_advice = (flags & ENABLE_ADVICE_PULL) && -+ advice_enabled(ADVICE_STATUS_HINTS); -+ bool enable_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE) && -+ advice_enabled(ADVICE_STATUS_HINTS); ++ bool use_push_advice = (flags & ENABLE_ADVICE_PUSH); ++ bool use_pull_advice = (flags & ENABLE_ADVICE_PULL); ++ bool use_divergence_advice = (flags & ENABLE_ADVICE_DIVERGENCE); + if (up_to_date) { strbuf_addf(sb, @@ 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 (enable_push_advice) ++ if (use_push_advice && advice_enabled(ADVICE_STATUS_HINTS)) 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 (enable_push_advice) ++ if (use_push_advice && advice_enabled(ADVICE_STATUS_HINTS)) 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 (enable_pull_advice) ++ if (use_pull_advice && advice_enabled(ADVICE_STATUS_HINTS)) 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 (enable_divergence_advice) ++ if (use_divergence_advice && advice_enabled(ADVICE_STATUS_HINTS)) strbuf_addstr(sb, _(" (use \"git pull\" if you want to integrate the remote branch with yours)\n")); } @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' + test_cmp expect actual +' + -+test_expect_success 'setup for compareBranches tests' ' -+ ( -+ cd test && -+ git config push.default current && -+ git config status.compareBranches "@{upstream} @{push}" -+ ) -+' -+ +test_expect_success 'status.compareBranches from upstream has no duplicates' ' -+ ( -+ cd test && -+ git checkout main && -+ git status >../actual -+ ) && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout main && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch main + Your branch is up to date with ${SQ}origin/main${SQ}. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches shows ahead of both upstream and push branch' ' -+ ( -+ cd test && -+ git checkout -b feature2 origin/main && -+ git push origin HEAD && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature2 origin/main && ++ git -C test push origin HEAD && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature2 + Your branch is ahead of ${SQ}origin/main${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'checkout with status.compareBranches shows both branches' ' -+ ( -+ cd test && -+ git checkout feature2 >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout feature2 >actual && + cat >expect <<-EOF && + Your branch is ahead of ${SQ}origin/main${SQ} by 1 commit. + @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches shows diverged and ahead' ' -+ ( -+ cd test && -+ git checkout feature4 && -+ git branch --set-upstream-to origin/main && -+ git push origin HEAD && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout feature4 && ++ git -C test branch --set-upstream-to origin/main && ++ git -C test push origin HEAD && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature4 + Your branch and ${SQ}origin/main${SQ} have diverged, @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status --no-ahead-behind with status.compareBranches' ' -+ ( -+ cd test && -+ git checkout feature4 && -+ git status --no-ahead-behind >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout feature4 && ++ git -C test status --no-ahead-behind >actual && + cat >expect <<-EOF && + On branch feature4 + Your branch and ${SQ}origin/main${SQ} refer to different commits. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' + ( + cd test && + git remote add upstream ../. && -+ git fetch upstream && -+ git config remote.pushDefault origin ++ git fetch upstream + ) +' + +test_expect_success 'status.compareBranches with upstream and origin remotes' ' -+ ( -+ cd test && -+ git checkout -b feature5 upstream/main && -+ git push origin && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature5 upstream/main && ++ git -C test push origin && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature5 + Your branch is ahead of ${SQ}upstream/main${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches supports ordered upstream/push entries' ' -+ ( -+ cd test && -+ git checkout -b feature6 upstream/main && -+ git push origin && -+ advance work && -+ git -c status.compareBranches="@{push} @{upstream}" status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{push} @{upstream}" && ++ git -C test checkout -b feature6 upstream/main && ++ git -C test push origin && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature6 + Your branch is ahead of ${SQ}origin/feature6${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches with diverged push branch' ' -+ ( -+ cd test && -+ git checkout -b feature7 upstream/main && -+ advance work && -+ git push origin && -+ git reset --hard upstream/main && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature7 upstream/main && ++ (cd test && advance work71) && ++ git -C test push origin && ++ git -C test reset --hard upstream/main && ++ (cd test && advance work72) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature7 + Your branch is ahead of ${SQ}upstream/main${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches shows up to date branches' ' -+ ( -+ cd test && -+ git checkout -b feature8 upstream/main && -+ git push origin && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature8 upstream/main && ++ git -C test push origin && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature8 + Your branch is up to date with ${SQ}upstream/main${SQ}. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status --no-ahead-behind with status.compareBranches up to date' ' -+ ( -+ cd test && -+ git checkout feature8 && -+ git push origin && -+ git status --no-ahead-behind >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout feature8 >actual && ++ git -C test push origin && ++ git -C test status --no-ahead-behind >actual && + cat >expect <<-EOF && + On branch feature8 + Your branch is up to date with ${SQ}upstream/main${SQ}. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'checkout with status.compareBranches shows up to date' ' -+ ( -+ cd test && -+ git checkout feature8 >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout feature8 >actual && + cat >expect <<-EOF && + Your branch is up to date with ${SQ}upstream/main${SQ}. + @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches with upstream behind and push up to date' ' -+ ( -+ cd test && -+ git checkout -b ahead upstream/main && -+ advance work && -+ git push upstream HEAD && -+ git checkout -b feature9 upstream/main && -+ git push origin && -+ git branch --set-upstream-to upstream/ahead && -+ git status >../actual -+ ) && ++ test_config -C test push.default current && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b ahead upstream/main && ++ (cd test && advance work) && ++ git -C test push upstream HEAD && ++ git -C test checkout -b feature9 upstream/main && ++ git -C test push origin && ++ git -C test branch --set-upstream-to upstream/ahead && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature9 + Your branch is behind ${SQ}upstream/ahead${SQ} by 1 commit, and can be fast-forwarded. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches with remapped push refspec' ' -+ ( -+ cd test && -+ git checkout -b feature10 origin/main && -+ git config remote.origin.push refs/heads/feature10:refs/heads/remapped && -+ git push && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test remote.origin.push refs/heads/feature10:refs/heads/remapped && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature10 origin/main && ++ git -C test push && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature10 + Your branch is ahead of ${SQ}origin/main${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' +' + +test_expect_success 'status.compareBranches with remapped push and upstream remote' ' -+ ( -+ cd test && -+ git checkout -b feature11 upstream/main && -+ git config remote.origin.push refs/heads/feature11:refs/heads/remapped && -+ git push origin && -+ advance work && -+ git status >../actual -+ ) && ++ test_config -C test remote.pushDefault origin && ++ test_config -C test remote.origin.push refs/heads/feature11:refs/heads/remapped && ++ test_config -C test status.compareBranches "@{upstream} @{push}" && ++ git -C test checkout -b feature11 upstream/main && ++ git -C test push origin && ++ (cd test && advance work) && ++ git -C test status >actual && + cat >expect <<-EOF && + On branch feature11 + Your branch is ahead of ${SQ}upstream/main${SQ} by 1 commit. @@ t/t6040-tracking-info.sh: test_expect_success '--set-upstream-to @{-1}' ' + EOF + test_cmp expect actual +' -+ -+test_expect_success 'clean up after compareBranches tests' ' -+ ( -+ cd test && -+ git config --unset status.compareBranches -+ ) -+' + test_done -- gitgitgadget