]> git.ipfire.org Git - thirdparty/git.git/commitdiff
remote: qualify "git pull" advice for non-upstream compareBranches
authorHarald Nordgren <haraldnordgren@gmail.com>
Thu, 21 May 2026 14:06:07 +0000 (14:06 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 22 May 2026 00:34:20 +0000 (09:34 +0900)
Enable ENABLE_ADVICE_PULL for push-branch comparisons too, not just
the upstream entry, so the "use git pull" hint prints when the local
branch is behind its push branch.

Spell out "git pull <remote> <branch>" so running the suggested
command actually pulls the ref the user was told about; plain
"git pull" would fetch the upstream instead.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
remote.c
t/t6040-tracking-info.sh

index a664cd166aa3b910c239645093782f7be475282f..8870598d44a8964a3b82695a4e9f190b2bc187ef 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -2267,6 +2267,8 @@ static void format_branch_comparison(struct strbuf *sb,
                                     bool up_to_date,
                                     int ours, int theirs,
                                     const char *branch_name,
+                                    const char *push_remote_name,
+                                    const char *push_branch_name,
                                     enum ahead_behind_flags abf,
                                     unsigned flags)
 {
@@ -2302,9 +2304,15 @@ static void format_branch_comparison(struct strbuf *sb,
                               "and can be fast-forwarded.\n",
                           theirs),
                        branch_name, theirs);
-               if (use_pull_advice && advice_enabled(ADVICE_STATUS_HINTS))
-                       strbuf_addstr(sb,
-                               _("  (use \"git pull\" to update your local branch)\n"));
+               if (use_pull_advice && advice_enabled(ADVICE_STATUS_HINTS)) {
+                       if (push_remote_name && push_branch_name)
+                               strbuf_addf(sb,
+                                       _("  (use \"git pull %s %s\" to update your local branch)\n"),
+                                       push_remote_name, push_branch_name);
+                       else
+                               strbuf_addstr(sb,
+                                       _("  (use \"git pull\" to update your local branch)\n"));
+               }
        } else {
                strbuf_addf(sb,
                        Q_("Your branch and '%s' have diverged,\n"
@@ -2315,9 +2323,15 @@ static void format_branch_comparison(struct strbuf *sb,
                               "respectively.\n",
                           ours + theirs),
                        branch_name, ours, theirs);
-               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"));
+               if (use_divergence_advice && advice_enabled(ADVICE_STATUS_HINTS)) {
+                       if (push_remote_name && push_branch_name)
+                               strbuf_addf(sb,
+                                       _("  (use \"git pull %s %s\" if you want to integrate the remote branch with yours)\n"),
+                                       push_remote_name, push_branch_name);
+                       else
+                               strbuf_addstr(sb,
+                                       _("  (use \"git pull\" if you want to integrate the remote branch with yours)\n"));
+               }
        }
 }
 
@@ -2355,6 +2369,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
                int ours, theirs, cmp;
                int is_upstream, is_push;
                unsigned flags = 0;
+               const char *push_remote_name = NULL;
+               const char *push_branch_name = NULL;
 
                full_ref = resolve_compare_branch(branch,
                                                  branches.items[i].string);
@@ -2398,11 +2414,27 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
 
                if (is_upstream)
                        flags |= ENABLE_ADVICE_PULL;
-               if (is_push)
-                       flags |= ENABLE_ADVICE_PUSH;
                if (show_divergence_advice && is_upstream)
                        flags |= ENABLE_ADVICE_DIVERGENCE;
+               if (is_push) {
+                       flags |= ENABLE_ADVICE_PUSH;
+                       if (!upstream_ref || strcmp(upstream_ref, full_ref)) {
+                               push_remote_name = pushremote_for_branch(branch, NULL);
+                               if (push_remote_name &&
+                                   skip_prefix(full_ref, "refs/remotes/", &push_branch_name) &&
+                                   skip_prefix(push_branch_name, push_remote_name, &push_branch_name) &&
+                                   *push_branch_name == '/') {
+                                       push_branch_name++;
+                                       flags |= ENABLE_ADVICE_PULL;
+                               } else {
+                                       push_remote_name = NULL;
+                               }
+                       } else {
+                               flags |= ENABLE_ADVICE_PULL;
+                       }
+               }
                format_branch_comparison(sb, !cmp, ours, theirs, short_ref,
+                                        push_remote_name, push_branch_name,
                                         abf, flags);
                reported = 1;
 
index 0242b5bf7abedbbad5e82ab2bf6199f5037a8ba3..91cbb8775d0a5a62791bbbf9f4b83d99d06a76ef 100755 (executable)
@@ -646,4 +646,104 @@ test_expect_success 'status.compareBranches with remapped push and upstream remo
        test_cmp expect actual
 '
 
+test_expect_success 'status.compareBranches behind both upstream and push' '
+       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 feature13 upstream/main &&
+       (cd test && advance work13) &&
+       git -C test push origin &&
+       git -C test branch --set-upstream-to upstream/ahead &&
+       git -C test reset --hard HEAD^ &&
+       git -C test status >actual &&
+       cat >expect <<-EOF &&
+       On branch feature13
+       Your branch is behind ${SQ}upstream/ahead${SQ} by 1 commit, and can be fast-forwarded.
+         (use "git pull" to update your local branch)
+
+       Your branch is behind ${SQ}origin/feature13${SQ} by 1 commit, and can be fast-forwarded.
+         (use "git pull origin feature13" to update your local branch)
+
+       nothing to commit, working tree clean
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches with remapped push and behind push branch' '
+       test_config -C test remote.pushDefault origin &&
+       test_config -C test remote.origin.push refs/heads/feature14:refs/heads/remapped14 &&
+       test_config -C test status.compareBranches "@{push}" &&
+       git -C test checkout -b feature14 upstream/main &&
+       (cd test && advance work14) &&
+       git -C test push &&
+       git -C test reset --hard HEAD^ &&
+       git -C test status >actual &&
+       cat >expect <<-EOF &&
+       On branch feature14
+       Your branch is behind ${SQ}origin/remapped14${SQ} by 1 commit, and can be fast-forwarded.
+         (use "git pull origin remapped14" to update your local branch)
+
+       nothing to commit, working tree clean
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches with behind push branch and no upstream' '
+       test_config -C test push.default current &&
+       test_config -C test remote.pushDefault origin &&
+       test_config -C test status.compareBranches "@{push}" &&
+       git -C test checkout --no-track -b feature15 upstream/main &&
+       (cd test && advance work15) &&
+       git -C test push origin &&
+       git -C test reset --hard HEAD^ &&
+       git -C test status >actual &&
+       cat >expect <<-EOF &&
+       On branch feature15
+       Your branch is behind ${SQ}origin/feature15${SQ} by 1 commit, and can be fast-forwarded.
+         (use "git pull origin feature15" to update your local branch)
+
+       nothing to commit, working tree clean
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches behind upstream-equals-push suggests plain pull' '
+       test_config -C test status.compareBranches "@{upstream} @{push}" &&
+       git -C test checkout -b feature16 origin/main &&
+       (cd test && advance work16) &&
+       git -C test push origin HEAD:main &&
+       git -C test reset --hard HEAD^ &&
+       git -C test status >actual &&
+       cat >expect <<-EOF &&
+       On branch feature16
+       Your branch is behind ${SQ}origin/main${SQ} by 1 commit, and can be fast-forwarded.
+         (use "git pull" to update your local branch)
+
+       nothing to commit, working tree clean
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'status.compareBranches suppresses advice when push tracking ref is unconventional' '
+       test_config -C test push.default current &&
+       test_config -C test remote.imported.url ../. &&
+       test_config -C test remote.imported.fetch "+refs/heads/*:refs/imported/imported/*" &&
+       test_config -C test branch.feature17.pushRemote imported &&
+       test_config -C test status.compareBranches "@{push}" &&
+       git -C test fetch imported &&
+       git -C test checkout --no-track -b feature17 refs/imported/imported/main &&
+       (cd test && advance work17) &&
+       git -C test push imported HEAD:feature17 &&
+       git -C test fetch imported &&
+       git -C test reset --hard HEAD^ &&
+       git -C test status >actual &&
+       cat >expect <<-EOF &&
+       On branch feature17
+       Your branch is behind ${SQ}imported/imported/feature17${SQ} by 1 commit, and can be fast-forwarded.
+
+       nothing to commit, working tree clean
+       EOF
+       test_cmp expect actual
+'
+
 test_done