Skip to content

remote: url-based pushRemote with renamed remotes#2358

Open
HaraldNordgren wants to merge 2 commits into
git:masterfrom
HaraldNordgren:remote-resolve-url-push-tracking
Open

remote: url-based pushRemote with renamed remotes#2358
HaraldNordgren wants to merge 2 commits into
git:masterfrom
HaraldNordgren:remote-resolve-url-push-tracking

Conversation

@HaraldNordgren

@HaraldNordgren HaraldNordgren commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Fix git status not showing the push branch after remotes are renamed, when branch.<name>.pushRemote is a URL matching exactly one configured remote.

Changes in v4:

  • Match configured remotes by effective push URL, preferring pushurl over url.
  • Update the documentation and rationale to describe where the remote would push.

Changes in v3:

  • Revamp commit messages to clarify motivation.

Changes in v2:

  • Clarify that URL push destinations already work and that this change only restores their tracking information.
  • Document URL values for branch.<name>.pushRemote and their @{push} behavior.

cc: "D. Ben Knoble" ben.knoble@gmail.com

@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from feaca5f to 7855ed3 Compare July 18, 2026 19:43
@HaraldNordgren HaraldNordgren changed the title remote resolve url push tracking remote: resolve url push tracking Jul 18, 2026
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from 7855ed3 to f1e8e0a Compare July 18, 2026 20:28
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch 3 times, most recently from e2a2d2a to ff645b2 Compare July 18, 2026 23:29
@HaraldNordgren

Copy link
Copy Markdown
Contributor Author

/submit

@gitgitgadget-git

Copy link
Copy Markdown

Submitted as pull.2358.git.git.1784538618.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v1

To fetch this version to local tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v1

Comment thread remote.c
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from ff645b2 to d36784d Compare July 20, 2026 19:03
@HaraldNordgren HaraldNordgren changed the title remote: resolve url push tracking remote: find tracking branches for URL push destinations Jul 20, 2026
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from d36784d to 83622ea Compare July 20, 2026 19:34
@HaraldNordgren HaraldNordgren changed the title remote: find tracking branches for URL push destinations remote: keep URL push tracking after renaming remotes Jul 20, 2026
@HaraldNordgren HaraldNordgren changed the title remote: keep URL push tracking after renaming remotes remote: handle push tracking after renaming remotes Jul 20, 2026
@HaraldNordgren HaraldNordgren changed the title remote: handle push tracking after renaming remotes remote: renamed remotes push tracking Jul 20, 2026
@HaraldNordgren HaraldNordgren changed the title remote: renamed remotes push tracking remote: renamed remote push tracking Jul 20, 2026
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from 83622ea to 6e924a7 Compare July 20, 2026 19:45
Comment thread Documentation/revisions.adoc
@HaraldNordgren

Copy link
Copy Markdown
Contributor Author

/submit

@gitgitgadget-git

Copy link
Copy Markdown

Submitted as pull.2358.v2.git.git.1784624306.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v2

To fetch this version to local tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v2:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v2

@gitgitgadget-git

Copy link
Copy Markdown

"D. Ben Knoble" wrote on the Git mailing list (how to reply to this email):

Hi Harald,

On Tue, Jul 21, 2026 at 5:08 AM Harald Nordgren via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> Keep git status showing the push branch after remotes are renamed by finding
> the configured remote with the same URL.
>
> Changes in v3:
>
>  * Revamp commit messages to clarify motivation.
>
> Changes in v2:
>
>  * Clarify that URL push destinations already work and that this change only
>    restores their tracking information.
>  * Document URL values for branch.<name>.pushRemote and their @{push}
>    behavior.
>
> Harald Nordgren (2):
>   remote: pass repository to push tracking helper
>   remote: find tracking branches for URL push destinations
>
>  Documentation/config/branch.adoc |   2 +
>  Documentation/revisions.adoc     |   3 +
>  remote.c                         |  36 +++++++++--
>  remote.h                         |   2 +
>  t/t5505-remote.sh                | 104 +++++++++++++++++++++++++++++++
>  transport.c                      |   5 +-
>  6 files changed, 146 insertions(+), 6 deletions(-)
>
>
> base-commit: 48bbf81c29ca9a4479ec7850fe206518682cdb2f
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2358%2FHaraldNordgren%2Fremote-resolve-url-push-tracking-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v2
> Pull-Request: https://github.com/git/git/pull/2358
>
> Range-diff vs v1:
>
>  1:  fc70895732 ! 1:  b1ac49de87 remote: pass repository to push tracking helper
>      @@ Metadata
>        ## Commit message ##
>           remote: pass repository to push tracking helper
>
>      -    The push tracking helper currently only needs the push remote. However,
>      -    resolving a URL-valued remote requires access to the repository's list
>      -    of configured remotes.
>      +    The next commit needs tracking_for_push_dest() to inspect the
>      +    repository's configured remotes. Pass the repository through the
>      +    existing callers and mark the new parameter as unused.
>
>      -    Pass the repository through the existing callers and mark the parameter
>      -    as unused for now. This prepares the helper for that lookup without
>      -    changing its behavior.
>      +    No change in behavior.
>
>           Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
>
>  2:  ff645b2159 ! 2:  6e924a7fec remote: resolve URL-valued push tracking remotes
>      @@ Metadata
>       Author: Harald Nordgren <haraldnordgren@gmail.com>
>
>        ## Commit message ##
>      -    remote: resolve URL-valued push tracking remotes
>      +    remote: find tracking branches for URL push destinations
>
>      -    A branch may name its push destination with a URL instead of a
>      -    configured remote. This is useful in fork workflows, where the original
>      -    remote is renamed to "upstream", the fork is added as "origin", and an
>      -    existing branch.<name>.pushRemote continues to contain the fork URL.
>      +    Git already accepts a repository URL as branch.<name>.pushRemote and
>      +    can push to it. When a configured remote has the same URL, however,
>      +    "git status" cannot show that remote's push branch.
>
>      -    Git can still push through the anonymous remote created for that URL.
>      -    However, the anonymous remote has no fetch refspec. Git therefore cannot
>      -    resolve @{push} to origin/<branch> or update that remote-tracking branch
>      -    after a push. The push can succeed, or report that everything is up to
>      -    date, while status continues to compare against a stale tracking ref or
>      -    cannot show the push branch at all.
>      +    This can happen in fork workflows when the original remote is renamed
>      +    to "upstream", the fork is added as "origin", and an existing
>      +    pushRemote value still contains the fork URL. The URL still points to
>      +    the right repository, so pushing works. However, @{push} is unavailable
>      +    because Git does not connect the URL to "origin". As a result,
>      +    "git status" cannot show the push branch, and an up-to-date push can
>      +    leave its local tracking information stale.

I'm a bit confused about the problem scenario here: if the pushRemote
value contains a URL, then renaming a remote has nothing to do with
it, right?

And if the pushRemote value contains a remote name, then renaming the
remote should propagate there as well, right? (At least, that's my
recollection of renaming; when I have used the GitHub CLI in the past
it has worked pretty well in that case, but maybe they've changed
things recently?)

I do think the URL<->remote matching for user display is a nice touch,
so I'm not against the series! Just want to understand the problem
statement well. Maybe I should read over the test cases, or you could
suggest a "how I hit this in the real world" recipe? (Explicit
commands are easier for me than natural language in that case.)

-- 
D. Ben Knoble

@gitgitgadget-git

Copy link
Copy Markdown

User "D. Ben Knoble" <ben.knoble@gmail.com> has been added to the cc: list.

Comment thread Documentation/revisions.adoc
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch 3 times, most recently from dad2acc to 88e039b Compare July 21, 2026 18:03
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch 4 times, most recently from bfaf38f to 9d5521e Compare July 21, 2026 18:43
@HaraldNordgren HaraldNordgren changed the title remote: renamed remote push tracking remote: url-based pushRemote with renamed remote Jul 21, 2026
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from 9d5521e to a343af9 Compare July 21, 2026 18:58
@HaraldNordgren HaraldNordgren changed the title remote: url-based pushRemote with renamed remote remote: url-based pushRemote with renamed remotes Jul 21, 2026
@gitgitgadget-git

Copy link
Copy Markdown

This branch is now known as hn/url-push-tracking.

@HaraldNordgren

Copy link
Copy Markdown
Contributor Author

/submit

@gitgitgadget-git

Copy link
Copy Markdown

Submitted as pull.2358.v3.git.git.1784664859.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v3

To fetch this version to local tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v3:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v3

@gitgitgadget-git

Copy link
Copy Markdown

Harald Nordgren wrote on the Git mailing list (how to reply to this email):

It's very valid and I need to explain it better if you are confused.



Harald

Comment thread Documentation/config/branch.adoc
The next commit needs tracking_for_push_dest() to inspect the
repository's configured remotes. Pass the repository through the
existing callers and mark the new parameter as unused.

No change in behavior.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch 2 times, most recently from 7902773 to b5736cd Compare July 22, 2026 05:47
Git accepts a repository URL as branch.<name>.pushRemote and can push
to it. This branch setting takes precedence over remote.pushDefault.

A branch can be configured with a URL-valued pushRemote before any push
occurs. If the remotes are later rearranged with "git remote rename" and
"git remote add", the newly added remote may use that URL. The URL value
is unaffected by the rename and continues to take precedence over
remote.pushDefault. The URL and the remote then point to the same
repository, but Git does not connect them for tracking. Pushing works,
but @{push} cannot identify the remote's tracking branch. As a result,
"git status" cannot show the push branch, and an up-to-date push can
leave its tracking information stale.

When exactly one configured remote would push to the same URL, use that
remote for push tracking. Continue to push to the URL so the configured
remote's push settings do not change existing behavior. Keep the current
behavior when no remote matches or multiple remotes match.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
@HaraldNordgren
HaraldNordgren force-pushed the remote-resolve-url-push-tracking branch from b5736cd to 08c432a Compare July 22, 2026 05:56
@gitgitgadget-git

Copy link
Copy Markdown

Ben Knoble wrote on the Git mailing list (how to reply to this email):

> Le 21 juil. 2026 à 16:14, Harald Nordgren via GitGitGadget <gitgitgadget@gmail.com> a écrit :
> 
> Fix git status not showing the push branch after remotes are renamed, when
> branch.<name>.pushRemote is a URL matching exactly one configured remote.
> 
> Changes in v4:
> 
> * Match against the actual push URL, including pushurl and pushInsteadOf.
> * Clarify how rearranging remotes exposes the git status tracking problem.
> * Simplify and correct the documentation for URL-valued pushRemote.
> 
> Changes in v3:
> 
> * Revamp commit messages to clarify motivation.
> 
> Changes in v2:
> 
> * Clarify that URL push destinations already work and that this change only
>   restores their tracking information.
> * Document URL values for branch.<name>.pushRemote and their @{push}
>   behavior.
> 
> Harald Nordgren (2):
>  remote: pass repository to push tracking helper
>  remote: find tracking branches for URL push destinations
> 
> Documentation/config/branch.adoc |   1 +
> Documentation/revisions.adoc     |   3 +
> remote.c                         |  43 +++++++++--
> remote.h                         |   2 +
> t/t5505-remote.sh                | 124 +++++++++++++++++++++++++++++++
> transport.c                      |   5 +-
> 6 files changed, 172 insertions(+), 6 deletions(-)
> 
> 
> base-commit: 48bbf81c29ca9a4479ec7850fe206518682cdb2f
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2358%2FHaraldNordgren%2Fremote-resolve-url-push-tracking-v3
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v3
> Pull-Request: https://github.com/git/git/pull/2358
> 
> Range-diff vs v2:
> 
> 1:  b1ac49de87 = 1:  b1ac49de87 remote: pass repository to push tracking helper
> 2:  6e924a7fec ! 2:  a343af9d50 remote: find tracking branches for URL push destinations
>     @@ Metadata
>       ## Commit message ##
>          remote: find tracking branches for URL push destinations
> 
>     -    Git already accepts a repository URL as branch.<name>.pushRemote and
>     -    can push to it. When a configured remote has the same URL, however,
>     -    "git status" cannot show that remote's push branch.
>     +    Git accepts a repository URL as branch.<name>.pushRemote and can push
>     +    to it. This branch setting takes precedence over remote.pushDefault.
> 
>     -    This can happen in fork workflows when the original remote is renamed
>     -    to "upstream", the fork is added as "origin", and an existing
>     -    pushRemote value still contains the fork URL. The URL still points to
>     -    the right repository, so pushing works. However, @{push} is unavailable
>     -    because Git does not connect the URL to "origin". As a result,
>     +    A branch can be configured with a URL-valued pushRemote before any push
>     +    occurs. If the remotes are later rearranged with "git remote rename" and
>     +    "git remote add", the newly added remote may use that URL. The URL value
>     +    is unaffected by the rename and continues to take precedence over
>     +    remote.pushDefault. The URL and the remote then point to the same
>     +    repository, but Git does not connect them for tracking. Pushing works,
>     +    but @{push} cannot identify the remote's tracking branch. As a result,
>          "git status" cannot show the push branch, and an up-to-date push can
>     -    leave its local tracking information stale.
>     +    leave its tracking information stale.
> 
>     -    When exactly one configured remote has the URL as one of its
>     -    remote.<name>.url values, use its fetch refspec to find and refresh the
>     -    push branch. Keep the URL as the push destination so the configured
>     -    remote's push settings do not change existing behavior. Keep the
>     -    current behavior when no remote matches or multiple remotes match.
>     +    When exactly one configured remote uses the push destination URL, use
>     +    that remote for push tracking. Continue to push to the URL so the
>     +    configured remote's push settings do not change existing behavior. Keep
>     +    the current behavior when no remote matches or multiple remotes match.
> 
>          Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>

I find this explanation makes more sense ; it’s not how I use remote renames, since I don’t usually use URL-valued remotes, but I can see how things arise now. Thanks!

@HaraldNordgren

Copy link
Copy Markdown
Contributor Author

/submit

@gitgitgadget-git

Copy link
Copy Markdown

Submitted as pull.2358.v4.git.git.1784743738.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v4

To fetch this version to local tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v4:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-2358/HaraldNordgren/remote-resolve-url-push-tracking-v4

@@ -55,6 +55,7 @@ This option defaults to `never`.
repository), you would want to set `remote.pushDefault` to

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> +static bool remote_has_push_url(struct remote *remote, const char *url)
> +{
> +	const struct strvec *push_urls = push_url_of_remote(remote);
> +
> +	for (size_t i = 0; i < push_urls->nr; i++) {
> +		if (!strcmp(push_urls->v[i], url))
> +			return true;
> +	}
> +	return false;
> +}

A new helper is very much welcome.

>  void ref_push_report_free(struct ref_push_report *report)
>  {
>  	while (report) {
> @@ -1887,13 +1898,45 @@ const char *branch_get_upstream(struct branch *branch, struct strbuf *err)
>  	return branch->merge[0]->dst;
>  }
>  
> -static char *tracking_for_push_dest(struct repository *repo UNUSED,
> +struct remote *repo_remote_for_push_tracking(struct repository *repo,
> +					     struct remote *remote)
> +{
> +	const struct strvec *push_urls;
> +	struct remote *first_match = NULL;
> +	struct remote_state *remote_state = repo->remote_state;
> +	const char *check_url;
> +
> +	if (remote->origin != REMOTE_UNCONFIGURED)
> +		return remote;
> +
> +	push_urls = push_url_of_remote(remote);
> +	if (push_urls->nr != 1)
> +		return remote;
> +	check_url = push_urls->v[0];
> +
> +	for (int i = 0; i < remote_state->remotes_nr; i++) {
> +		struct remote *candidate = remote_state->remotes[i];
> +
> +		if (!candidate || candidate == remote ||
> +		    !remote_is_configured(candidate, 0) ||
> +		    !remote_has_push_url(candidate, check_url))

This part used to use remote_has_url(candidate, remote->url.v[0]),
which only looked at the .url and ignored .pushurl.  Now it uses
remote_has_push_url() so we grab the effective push URL for the
remote we are dealing with and match it against the effective push
URL of the candidates.  Looks correct.

> diff --git a/transport.c b/transport.c
> index fc144f0aed..30a4ab2cd5 100644
> --- a/transport.c
> +++ b/transport.c
> @@ -1553,8 +1553,11 @@ int transport_push(struct repository *r,
>  	if (!(flags & (TRANSPORT_PUSH_DRY_RUN |
>  		       TRANSPORT_RECURSE_SUBMODULES_ONLY))) {
>  		struct ref *ref;
> +		struct remote *tracking_remote = repo_remote_for_push_tracking(
> +			r, transport->remote);

Personally, I would have line-wrapped the above more like this:

		struct remote *tracking_remote =
			repo_remote_for_push_tracking(r, transport->remote);

This is just for a future reference; it is certainly not critical
enough to warrant a new iteration just for this.

Thanks.

@gitgitgadget-git

Copy link
Copy Markdown

This patch series was integrated into seen via a2a3c4e.

@gitgitgadget-git

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> Fix git status not showing the push branch after remotes are renamed, when
> branch.<name>.pushRemote is a URL matching exactly one configured remote.
>
> Changes in v4:
>
>  * Match configured remotes by effective push URL, preferring pushurl over
>    url.
>  * Update the documentation and rationale to describe where the remote would
>    push.

My cursory review did not spot anything obviously wrong anymore.

As it somehow seems to be a slow week, I do not expect to see many
eyeballs from others helping to review the topics in flight as
quickly as we would have liked to move them forward, though.

Thanks.

@gitgitgadget-git

Copy link
Copy Markdown

There was a status update in the "Cooking" section about the branch hn/url-push-tracking on the Git mailing list:

When the push remote is specified as a URL, the fetch refspec of a
uniquely matching configured remote is now used to find and update
the remote-tracking branch (e.g., '@{push}').

Will merge to 'next'?
cf. <xmqqpl0eoniz.fsf@gitster.g>
cf. <3FE12592-B663-438C-B33E-A251AE08E146@gmail.com>
source: <pull.2358.v4.git.git.1784743738.gitgitgadget@gmail.com>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant