git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/2] branch: suggest <remote>/<branch> on upstream slip

From
Harald Nordgren via GitGitGadget <gitgitgadget@gmail.com>
Date
Jun 12, 2026, 11:10 UTC
Message-ID
<21684539debaf433b6b63404e1a7622a5cc33283.1781262619.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.2331.git.git.1781262619.gitgitgadget@gmail.com>
From: Harald Nordgren <haraldnordgren@gmail.com>

"git branch --set-upstream-to origin main" reads the trailing word as the local branch to operate on and dies with "branch 'main' does not exist", pointing at the wrong problem.

When that branch is missing and "<remote>/<branch>" names a real remote-tracking ref, suggest the intended "git branch --set-upstream-to=<remote>/<branch>" form.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
 builtin/branch.c  | 17 +++++++++++++++++
 t/t3200-branch.sh | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
diff --git a/builtin/branch.c b/builtin/branch.c
index 1572a4f9ef..7ad3efb908 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -957,6 +957,23 @@ int cmd_branch(int argc,
 		if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) {
 			if (!argc || branch_checked_out(branch->refname))
 				die(_("no commit on branch '%s' yet"), branch->name);
+			if (argc == 1 && !strchr(new_upstream, '/') &&
+			    remote_is_configured(remote_get(new_upstream), 0)) {
+				struct strbuf remote_ref = STRBUF_INIT;
+
+				strbuf_addf(&remote_ref, "refs/remotes/%s/%s",
+					    new_upstream, argv[0]);
+				if (refs_ref_exists(get_main_ref_store(the_repository),
+						    remote_ref.buf)) {
+					int code = die_message(_("--set-upstream-to takes a single <remote>/<branch> argument"));
+					advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
+							  _("Did you mean to use: git branch --set-upstream-to=%s/%s?"),
+							  new_upstream, argv[0]);
+					strbuf_release(&remote_ref);
+					exit(code);
+				}
+				strbuf_release(&remote_ref);
+			}
 			die(_("branch '%s' does not exist"), branch->name);
 		}
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index e7829c2c4b..e2682a83a0 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -1022,6 +1022,44 @@ test_expect_success '--set-upstream-to fails on a missing dst branch' '
 	test_cmp expect err
 '
 
+test_expect_success '--set-upstream-to suggests <remote>/<branch> on slip' '
+	test_when_finished "git remote remove slip-remote" &&
+	git remote add slip-remote . &&
+	git update-ref refs/remotes/slip-remote/slip-feature HEAD &&
+	test_must_fail git branch --set-upstream-to slip-remote slip-feature 2>err &&
+	test_grep "takes a single <remote>/<branch> argument" err &&
+	test_grep "hint: Did you mean to use: git branch --set-upstream-to=slip-remote/slip-feature?" err &&
+	test_must_fail git -c advice.setUpstreamFailure=false \
+		branch --set-upstream-to slip-remote slip-feature 2>err &&
+	test_grep ! "Did you mean" err
+'
+
+test_expect_success '--set-upstream-to does not suggest when no matching remote ref' '
+	test_when_finished "git remote remove slip-remote" &&
+	git remote add slip-remote . &&
+	test_must_fail git branch --set-upstream-to slip-remote no-such-branch 2>err &&
+	test_grep "branch ${SQ}no-such-branch${SQ} does not exist" err &&
+	test_grep ! "Did you mean" err
+'
+
+test_expect_success '--set-upstream-to to a local branch is not mistaken for a slip' '
+	git branch slip-local-upstream &&
+	git branch slip-local-target &&
+	git branch --set-upstream-to=slip-local-upstream slip-local-target 2>err &&
+	test_grep ! "Did you mean" err &&
+	echo refs/heads/slip-local-upstream >expect &&
+	git config branch.slip-local-target.merge >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '--set-upstream-to slip suggestion keeps a slashed branch name' '
+	test_when_finished "git remote remove slip-remote" &&
+	git remote add slip-remote . &&
+	git update-ref refs/remotes/slip-remote/slip/feature HEAD &&
+	test_must_fail git branch --set-upstream-to slip-remote slip/feature 2>err &&
+	test_grep "hint: Did you mean to use: git branch --set-upstream-to=slip-remote/slip/feature?" err
+'
+
 test_expect_success '--set-upstream-to fails on a missing src branch' '
 	test_must_fail git branch --set-upstream-to does-not-exist main 2>err &&
 	test_grep "the requested upstream branch '"'"'does-not-exist'"'"' does not exist" err
-- 
gitgitgadget
Previous: Harald Nordgren via GitGitGadgetNext: Junio C Hamano
Message 2 of 26 in “branch/push: suggest intended form when remote/branch slip given”
  1. 0/2 branch/push: suggest intended form when remote/branch slip givenHarald Nordgren via GitGitGadget, Jun 12, 2026
  2. 1/2 branch: suggest <remote>/<branch> on upstream slipHarald Nordgren via GitGitGadget, Jun 12, 2026
  3. Junio C HamanoJun 22, 2026
  4. Junio C HamanoJun 22, 2026
  5. Ben KnobleJun 24, 2026
  6. 2/2 push: suggest <remote> <branch> for a slash slipHarald Nordgren via GitGitGadget, Jun 12, 2026
  7. Junio C HamanoJun 22, 2026
  8. Harald NordgrenJun 22, 2026
  9. Weijie YuanJun 22, 2026
  10. Junio C HamanoJun 22, 2026
  11. Harald NordgrenJun 23, 2026
  12. 0/2 branch/push: suggest intended form when remote/branch slip givenHarald Nordgren via GitGitGadget, Jun 24, 2026
  13. 1/2 branch: suggest <remote>/<branch> on upstream slipHarald Nordgren via GitGitGadget, Jun 24, 2026
  14. Junio C HamanoJun 24, 2026
  15. Harald NordgrenJun 25, 2026
  16. Junio C HamanoJun 25, 2026
  17. 2/2 push: suggest <remote> <branch> for a slash slipHarald Nordgren via GitGitGadget, Jun 24, 2026
  18. Junio C HamanoJun 24, 2026
  19. Junio C HamanoJun 25, 2026
  20. Harald NordgrenJun 25, 2026
  21. Junio C HamanoJun 25, 2026
  22. 0/2 branch/push: suggest intended form when remote/branch slip givenHarald Nordgren via GitGitGadget, Jun 27, 2026
  23. 1/2 branch: suggest <remote>/<branch> on upstream slipHarald Nordgren via GitGitGadget, Jun 27, 2026
  24. Junio C HamanoJun 28, 2026
  25. Harald NordgrenJun 28, 2026
  26. 2/2 push: suggest <remote> <branch> for a slash slipHarald Nordgren via GitGitGadget, Jun 27, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.