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

[PATCH] remote: resolve "simple" @{push} when pushing to another remote

From
Harald Nordgren via GitGitGadget <gitgitgadget@gmail.com>
Date
Oct 27, 2026, 12:43 UTC
Message-ID
<pull.2466.git.git.1793105039624.gitgitgadget@gmail.com>
From: Harald Nordgren <haraldnordgren@gmail.com>

With push.default left at "simple", a branch whose upstream is on one remote and whose push remote is another gets pushed by "git push" to a branch of the same name on the push remote. But @{push} for that branch fails with "cannot resolve 'simple' push to a single destination". As a result "git status" shows the "git push" hint under the comparison with the upstream, even though "git push" goes elsewhere, and leaves out the comparison with the push branch when status.compareBranches asks for it.

"git push" learned to handle "simple" this way in ed2b18292b (push: change `simple` to accommodate triangular workflows, 2013-06-19). When @{push} was added in e291c75a95 (remote.c: add branch_get_push, 2015-05-21), its "simple" case only covered pushing back to the remote the branch is fetched from, where the upstream must have the same name.

Make @{push} follow "git push". When the push remote is not the remote of the branch, resolve to the branch of the same name on the push remote, as "current" does.

The test added in 9bf9eed093 (remote: fix leak in branch_get_push_1() with invalid "simple" config, 2026-01-19) relied on a different push remote being invalid for "simple". Use an upstream with a different name on the same remote instead, so that it still exercises the error path.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
    remote: resolve "simple" @{push} when pushing to another remote
    
    With push.default=simple and remote.pushDefault pointing at a fork, git
    push pushes the branch to the fork, but @{push} fails with "cannot
    resolve 'simple' push to a single destination".
    
    So git status cannot compare the branch with where it was pushed. Make
    @{push} resolve to where git push goes.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2466%2FHaraldNordgren%2Fat-push-simple-triangular-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2466/HaraldNordgren/at-push-simple-triangular-v1
Pull-Request: https://github.com/git/git/pull/2466
 remote.c                  |  4 ++++
 t/for-each-ref-tests.sh   |  4 +++-
 t/t1514-rev-parse-push.sh | 11 +++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/remote.c b/remote.c
index 49ee2ea318..fd434a3a10 100644
--- a/remote.c
+++ b/remote.c
@@ -2016,6 +2016,10 @@ static char *branch_get_push_1(struct repository *repo,
 			const char *up;
 			char *cur;
 
+			if (strcmp(remote->name,
+				   remotes_remote_for_branch(remote_state, branch, NULL)))
+				return tracking_for_push_dest(repo, remote, branch->refname, err);
+
 			up = branch_get_upstream(branch, err);
 			if (!up)
 				return NULL;
diff --git a/t/for-each-ref-tests.sh b/t/for-each-ref-tests.sh
index b1a10dd933..4991a82b91 100644
--- a/t/for-each-ref-tests.sh
+++ b/t/for-each-ref-tests.sh
@@ -1745,9 +1745,11 @@ test_expect_success ':remotename and :remoteref' '
 '
 
 test_expect_success '%(push) with an invalid push-simple config' '
+	test_when_finished "git config branch.main.merge refs/heads/main" &&
+	git config branch.main.merge refs/heads/not-main &&
 	echo "refs/heads/main " >expect &&
 	git -c push.default=simple \
-	    -c remote.pushdefault=myfork \
+	    -c remote.pushdefault=origin \
 	    for-each-ref \
 	    --format="%(refname) %(push)" refs/heads/main >actual &&
 	test_cmp expect actual
diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh
index 5a4f16867a..4187e2a504 100755
--- a/t/t1514-rev-parse-push.sh
+++ b/t/t1514-rev-parse-push.sh
@@ -60,6 +60,17 @@ test_expect_success '@{push} with pushremote defined' '
 	resolve topic@{push} refs/remotes/other/topic
 '
 
+test_expect_success 'triangular @{push} with default=simple and remote.pushdefault' '
+	test_config push.default simple &&
+	test_config remote.pushdefault other &&
+	test_when_finished "git checkout main" &&
+	git checkout topic &&
+	test_commit simple-triangular &&
+	git push &&
+	resolve topic@{push} refs/remotes/other/topic &&
+	test_cmp_rev topic topic@{push}
+'
+
 test_expect_success '@{p} is short for @{push}' '
 	test_config push.default current &&
 	test_config branch.topic.pushremote other &&

base-commit: 7e34d8174dcda3435d1404c9a30bef46afe6c13e
-- 
gitgitgadget
Next: D. Ben Knoble
Message 1 of 4 in “remote: resolve "simple" @{push} when pushing to another remote”
  1. remote: resolve "simple" @{push} when pushing to another remoteHarald Nordgren via GitGitGadget, Oct 27, 2026
  2. D. Ben KnobleOct 28, 2026
  3. Harald NordgrenOct 29, 2026
  4. Junio C HamanoOct 29, 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.