Re: Cannot override `remote.origin.url` with `-c` option
From: Jeff King <hidden>
Date: 2024-06-11 07:51:38
Subsystem:
the rest · Maintainer:
Linus Torvalds
On Sun, Jun 09, 2024 at 12:21:47PM +0530, Mathew George wrote:
quoted
What did you expect to happen? (Expected behavior)The '-c' option should allow me to override the remote URL, which, as a result of running `git remote add`, is configured as follows in test/.git/config:[remote "origin"] url = wrong-url
I don't think "-c" is the culprit here, but rather that remote.*.url is
a multi-valued config option. Rather than having a single value with
"last one wins" semantics, multiple instances of the config variable
form a list. So you'd see the same thing with:
[remote "origin"]
url = wrong-url
url = right-url
in the config file.
Of course that leaves two questions:
1. What are multiple URLs actually good for? I have no idea. I
couldn't find any useful documentation in the manpages for
git-config, git-remote, or git-fetch. It looks like any URLs after
the first are used as push-only URLs:
$ git remote show -n origin
* remote origin
Fetch URL: wrong-url
Push URL: wrong-url
Push URL: right-url
[...]
There's also a "pushurl" config option, which _replaces_ the
original URL for pushing, rather than including it.
As far as I can tell there's no way to actually have multiple fetch
URLs (and the corner cases would be weird anyway). I suspect we'd
come up with different semantics if we were designing it these
days, but it has been this way since at least 2007. So any changes
would probably need a deprecation period.
2. Is there a way to override the list?
Sadly, no. For some config keys, we allow a value-less boolean
entry to reset the list. But since the config code doesn't know
about the semantics of each key, this has to be implemented
individually for each key, and nobody has bothered to do so for
remote.*.url.
The value-less key is something like:
[remote "origin"]
url = wrong-url
# this one resets the list to empty!
url
# and this one adds a new value
url = right-url
Or in "-c" terms, it would be:
git -c remote.origin.url -c remote.origin.url=right-url ...
The syntax is ugly, but it is backwards compatible (that value-less
entry is currently an error). So we could do that now (I'll show a
messy patch below).
Of course none of that helps your immediate case. I did think of one
workaround, though, which is to use the "insteadOf" config to rewrite
the URL. So:
git -c url.right-url.insteadOf=wrong-url ...
will rewrite all instances of "wrong-url" to use "right-url" instead (in
origin and elsewhere).
-Peff
---diff --git a/remote.c b/remote.c
index dcb5492c85..69b0f28637 100644
--- a/remote.c
+++ b/remote.c@@ -63,6 +63,10 @@ static const char *alias_url(const char *url, struct rewrites *r) static void add_url(struct remote *remote, const char *url) { + if (!url) { + remote->url_nr = 0; + return; + } ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); remote->url[remote->url_nr++] = url; }
@@ -430,10 +434,7 @@ static int handle_config(const char *key, const char *value, else if (!strcmp(subkey, "prunetags")) remote->prune_tags = git_config_bool(key, value); else if (!strcmp(subkey, "url")) { - char *v; - if (git_config_string(&v, key, value)) - return -1; - add_url(remote, v); + add_url(remote, xstrdup_or_null(value)); } else if (!strcmp(subkey, "pushurl")) { char *v; if (git_config_string(&v, key, value))