Git development
 help / color / mirror / Atom feed
From: "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "D. Ben Knoble" <ben.knoble@gmail.com>,
	Harald Nordgren <haraldnordgren@gmail.com>
Subject: [PATCH v3 0/2] remote: url-based pushRemote with renamed remotes
Date: Tue, 21 Jul 2026 20:14:17 +0000	[thread overview]
Message-ID: <pull.2358.v3.git.git.1784664859.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2358.v2.git.git.1784624306.gitgitgadget@gmail.com>

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>
      
     @@ Documentation/config/branch.adoc: This option defaults to `never`.
       	repository), you would want to set `remote.pushDefault` to
       	specify the remote to push to for all branches, and use this
       	option to override it for a specific branch.
     -+	The value may be the name of a configured remote or a repository
     -+	URL. A URL is used directly as the push destination.
     ++	The value may be the name of a configured remote or a repository URL.
       
       `branch.<name>.merge`::
       	Defines, together with `branch.<name>.remote`, the upstream branch
     @@ Documentation/revisions.adoc: some output processing may assume ref names in UTF
         `git push` were run while `branchname` was checked out (or the current
         `HEAD` if no branchname is specified). Like for '@\{upstream\}', we report
         the remote-tracking branch that corresponds to that branch at the remote.
     -+  If the push destination is a URL and exactly one configured remote has the
     -+  same `remote.<name>.url`, '@\{push}' reports the remote-tracking branch for
     -+  that remote.
     ++  If the push destination is a URL and exactly one configured remote has
     ++  that URL among its `remote.<name>.url` values, '@\{push}' reports that
     ++  remote's remote-tracking branch.
       +
       Here's an example to make it more clear:
       +
     @@ remote.c: const char *branch_get_upstream(struct branch *branch, struct strbuf *
      +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 || remote->url.nr != 1)
     ++	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_url(candidate, remote->url.v[0]))
     ++		    !remote_has_url(candidate, check_url))
      +			continue;
      +		if (first_match)
      +			return remote;
     @@ t/t5505-remote.sh: setup_repository () {
      +	rm -rf fork.git client &&
      +	git clone --bare one fork.git &&
      +	git clone one client &&
     -+	fork_url="$TRASH_DIRECTORY/fork.git" &&
     ++	fork_url="file://$TRASH_DIRECTORY/fork.git" &&
      +	(
      +		cd client &&
      +		git checkout -b topic --track origin/main &&
     @@ t/t5505-remote.sh: test_expect_success 'rename a remote renames repo remote.push
      +	EOF
      +'
      +
     -+test_expect_success 'adding fork remote makes URL-valued pushRemote trackable' '
     ++test_expect_success 'adding matching remote makes URL-valued pushRemote trackable' '
      +	setup_url_pushremote &&
      +
      +	(
     @@ t/t5505-remote.sh: test_expect_success 'rename a remote renames repo remote.push
      +	EOF
      +'
      +
     ++test_expect_success 'pushInsteadOf URL pushRemote is trackable' '
     ++	setup_url_pushremote &&
     ++	(
     ++		cd client &&
     ++		git remote rename origin upstream &&
     ++		git remote add -f origin "$fork_url" &&
     ++		git config "url.$fork_url.pushInsteadOf" fork: &&
     ++		git config branch.topic.pushRemote fork:
     ++	) &&
     ++
     ++	check_status <<-EOF
     ++	On branch topic
     ++	Your branch is ahead of ${SQ}upstream/main${SQ} by 1 commit.
     ++
     ++	Your branch is up to date with ${SQ}origin/topic${SQ}.
     ++
     ++	nothing to commit, working tree clean
     ++	EOF
     ++'
     ++
      +test_expect_success 'up-to-date URL push refreshes stale tracking branch' '
      +	setup_url_pushremote &&
      +	(

-- 
gitgitgadget

  parent reply	other threads:[~2026-07-21 20:14 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-20  9:10 [PATCH 0/2] remote: resolve url push tracking Harald Nordgren via GitGitGadget
2026-07-20  9:10 ` [PATCH 1/2] remote: pass repository to push tracking helper Harald Nordgren via GitGitGadget
2026-07-20 18:23   ` Junio C Hamano
2026-07-20  9:10 ` [PATCH 2/2] remote: resolve URL-valued push tracking remotes Harald Nordgren via GitGitGadget
2026-07-20 18:49   ` Junio C Hamano
2026-07-20 19:56     ` Harald Nordgren
2026-07-20 23:49       ` Junio C Hamano
2026-07-21 16:11   ` Junio C Hamano
2026-07-21  8:58 ` [PATCH v2 0/2] remote: renamed remote push tracking Harald Nordgren via GitGitGadget
2026-07-21  8:58   ` [PATCH v2 1/2] remote: pass repository to push tracking helper Harald Nordgren via GitGitGadget
2026-07-21  8:58   ` [PATCH v2 2/2] remote: find tracking branches for URL push destinations Harald Nordgren via GitGitGadget
2026-07-21 14:28   ` [PATCH v2 0/2] remote: renamed remote push tracking D. Ben Knoble
2026-07-21 20:10     ` Harald Nordgren
2026-07-21 20:14   ` Harald Nordgren via GitGitGadget [this message]
2026-07-21 20:14     ` [PATCH v3 1/2] remote: pass repository to push tracking helper Harald Nordgren via GitGitGadget
2026-07-21 20:14     ` [PATCH v3 2/2] remote: find tracking branches for URL push destinations Harald Nordgren via GitGitGadget
2026-07-21 22:15       ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pull.2358.v3.git.git.1784664859.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=ben.knoble@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=haraldnordgren@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox