[PATCH v30 0/2] status: add status.compareBranches config for multiple branch comparisons
From: Harald Nordgren via GitGitGadget <hidden>
Date: 2026-02-26 10:33:45
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