git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Allowing "/" in the name of a git remote is a strange choice
@ 2025-07-03 19:33 Per Cederqvist
  2025-07-04  4:51 ` Junio C Hamano
  2025-07-05 16:57 ` Jeff King
  0 siblings, 2 replies; 18+ messages in thread
From: Per Cederqvist @ 2025-07-03 19:33 UTC (permalink / raw)
  To: git; +Cc: Per Cederqvist

Today I realized that git accepts "/" in a remote name.

This can lead to problems. I have a repository that contains a branch
called "master" and another called "chat/master". Just for fun, I
added a second remote in this repository and named it
"origin/chat".

Now, does "refs/remotes/origin/chat/master" refer to the branch
"chat/master" from "origin", or the branch "master" from
"origin/chat"? Git seems to think it refers to both:

> $ git fetch --all
> Fetching origin
> From $PRIVATE_URL
>  + 4e31956300f...30e26ebbb19 chat/master -> origin/chat/master  (forced update)
> Fetching origin/chat
> From  $PRIVATE_URL
>  + 30e26ebbb19...4e31956300f master     -> origin/chat/master  (forced update)

Every time I run "git fetch --all" git updates the origin/chat/master ref twice.

If it was up to me, I'd add a check to valid_remote_name() to ensure
the name doesn't contain any "/" character.  I doubt it is used often.

    /ceder

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-03 19:33 Allowing "/" in the name of a git remote is a strange choice Per Cederqvist
@ 2025-07-04  4:51 ` Junio C Hamano
  2025-07-04  5:13   ` Patrick Steinhardt
  2025-07-04  6:42   ` Per Cederqvist
  2025-07-05 16:57 ` Jeff King
  1 sibling, 2 replies; 18+ messages in thread
From: Junio C Hamano @ 2025-07-04  4:51 UTC (permalink / raw)
  To: Per Cederqvist; +Cc: git

Per Cederqvist <ceder@lysator.liu.se> writes:

> Today I realized that git accepts "/" in a remote name.
>
> This can lead to problems. I have a repository that contains a branch
> called "master" and another called "chat/master". Just for fun, I
> added a second remote in this repository and named it
> "origin/chat".
>
> Now, does "refs/remotes/origin/chat/master" refer to the branch
> "chat/master" from "origin", or the branch "master" from
> "origin/chat"? Git seems to think it refers to both:

That would have been a fun experiment ;-)

> If it was up to me, I'd add a check to valid_remote_name() to ensure
> the name doesn't contain any "/" character.  I doubt it is used often.

If your remote-naming discipline is to always use two-levels
(e.g. origin/chat, origin/chien, origin/lapin but never origin or
origin/chat/blanc mixed in), then there is no confusion.

It becomes only confusing if you mix origin and origin/chat.  

So it is not like we can just forbid '/' retroactively and expect no
repercussions, especially given that I hear there are more than a
few thousands of existing Git users in the world.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-04  4:51 ` Junio C Hamano
@ 2025-07-04  5:13   ` Patrick Steinhardt
  2025-07-04  8:10     ` Lidong Yan
                       ` (2 more replies)
  2025-07-04  6:42   ` Per Cederqvist
  1 sibling, 3 replies; 18+ messages in thread
From: Patrick Steinhardt @ 2025-07-04  5:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Per Cederqvist, git

On Thu, Jul 03, 2025 at 09:51:12PM -0700, Junio C Hamano wrote:
> Per Cederqvist <ceder@lysator.liu.se> writes:
> 
> > Today I realized that git accepts "/" in a remote name.
> >
> > This can lead to problems. I have a repository that contains a branch
> > called "master" and another called "chat/master". Just for fun, I
> > added a second remote in this repository and named it
> > "origin/chat".
> >
> > Now, does "refs/remotes/origin/chat/master" refer to the branch
> > "chat/master" from "origin", or the branch "master" from
> > "origin/chat"? Git seems to think it refers to both:
> 
> That would have been a fun experiment ;-)
> 
> > If it was up to me, I'd add a check to valid_remote_name() to ensure
> > the name doesn't contain any "/" character.  I doubt it is used often.
> 
> If your remote-naming discipline is to always use two-levels
> (e.g. origin/chat, origin/chien, origin/lapin but never origin or
> origin/chat/blanc mixed in), then there is no confusion.
> 
> It becomes only confusing if you mix origin and origin/chat.  
> 
> So it is not like we can just forbid '/' retroactively and expect no
> repercussions, especially given that I hear there are more than a
> few thousands of existing Git users in the world.

We cannot just blanket-disallow this now, true. But shouldn't Git be
able to detect this conflict, similar to how a user cannot have both
refs/heads/branch and refs/heads/branch/nested?

Patrick

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-04  4:51 ` Junio C Hamano
  2025-07-04  5:13   ` Patrick Steinhardt
@ 2025-07-04  6:42   ` Per Cederqvist
  1 sibling, 0 replies; 18+ messages in thread
From: Per Cederqvist @ 2025-07-04  6:42 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Fri, Jul 4, 2025 at 6:51 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Per Cederqvist <ceder@lysator.liu.se> writes:
>
> > Today I realized that git accepts "/" in a remote name.
> >
> > This can lead to problems. I have a repository that contains a branch
> > called "master" and another called "chat/master". Just for fun, I
> > added a second remote in this repository and named it
> > "origin/chat".
> >
> > Now, does "refs/remotes/origin/chat/master" refer to the branch
> > "chat/master" from "origin", or the branch "master" from
> > "origin/chat"? Git seems to think it refers to both:
>
> That would have been a fun experiment ;-)

It was. Luckily I figured this out while trying to deduce the allowed format
of a remote name by reading the source code, not while trying to understand
confusing behaviour from git.

> > If it was up to me, I'd add a check to valid_remote_name() to ensure
> > the name doesn't contain any "/" character.  I doubt it is used often.
>
> If your remote-naming discipline is to always use two-levels
> (e.g. origin/chat, origin/chien, origin/lapin but never origin or
> origin/chat/blanc mixed in), then there is no confusion.
>
> It becomes only confusing if you mix origin and origin/chat.
>
> So it is not like we can just forbid '/' retroactively and expect no
> repercussions, especially given that I hear there are more than a
> few thousands of existing Git users in the world.

I wonder how many use "/" in a remote name, though. My guess is
very few.

If you want to do anything about this, there are a few possible ways:

- forbid "/", but add a setting that allows it. Note that even if you forbid
  "/", existing clones will continue to work. It is only when you add a
  new remote that the name is checked.

- require that the number of "/" character in a remote is equal for all
   remotes in a particular clone

- deperecate "/" and start warning about it now, and forbid it after a
suitable period

    /ceder

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-04  5:13   ` Patrick Steinhardt
@ 2025-07-04  8:10     ` Lidong Yan
  2025-07-04  8:17     ` Lidong Yan
  2025-07-04 14:18     ` Junio C Hamano
  2 siblings, 0 replies; 18+ messages in thread
From: Lidong Yan @ 2025-07-04  8:10 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: Junio C Hamano, Per Cederqvist, git

Patrick Steinhardt <ps@pks.im> writes:

> We cannot just blanket-disallow this now, true. But shouldn't Git be
> able to detect this conflict, similar to how a user cannot have both
> refs/heads/branch and refs/heads/branch/nested?

Perhaps we should forbid having two remotes where one is the directory base
(i.e., a prefix) of the other.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-04  5:13   ` Patrick Steinhardt
  2025-07-04  8:10     ` Lidong Yan
@ 2025-07-04  8:17     ` Lidong Yan
  2025-07-04 14:18     ` Junio C Hamano
  2 siblings, 0 replies; 18+ messages in thread
From: Lidong Yan @ 2025-07-04  8:17 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: Junio C Hamano, Per Cederqvist, git

Patrick Steinhardt <ps@pks.im> write:
> 
> We cannot just blanket-disallow this now, true. But shouldn't Git be
> able to detect this conflict, similar to how a user cannot have both
> refs/heads/branch and refs/heads/branch/nested?
> 

I also find `git fetch` works fine, but check out remote branch detect this
conflict

$ git branch --set-upstream-to=origin/chat/master chat/master

Gives

fatal: not tracking: ambiguous information for ref 'refs/remotes/origin/chat/master'
hint: There are multiple remotes whose fetch refspecs map to the remote
hint: tracking ref 'refs/remotes/origin/chat/master':
hint:   origin/chat
hint:   origin
hint: 
hint: This is typically a configuration error.
hint: 
hint: To support setting up tracking branches, ensure that
hint: different remotes' fetch refspecs map into different
hint: tracking namespaces


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-04  5:13   ` Patrick Steinhardt
  2025-07-04  8:10     ` Lidong Yan
  2025-07-04  8:17     ` Lidong Yan
@ 2025-07-04 14:18     ` Junio C Hamano
  2 siblings, 0 replies; 18+ messages in thread
From: Junio C Hamano @ 2025-07-04 14:18 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: Per Cederqvist, git

Patrick Steinhardt <ps@pks.im> writes:

>> So it is not like we can just forbid '/' retroactively and expect no
>> repercussions, especially given that I hear there are more than a
>> few thousands of existing Git users in the world.
>
> We cannot just blanket-disallow this now, true. But shouldn't Git be
> able to detect this conflict, similar to how a user cannot have both
> refs/heads/branch and refs/heads/branch/nested?

Yup.  Sorry but I should probably have not left it out, as that was
way too obvious an improved "solution", compared to "just forbid '/',
as I cannot imagine anybody using it".

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Allowing "/" in the name of a git remote is a strange choice
  2025-07-03 19:33 Allowing "/" in the name of a git remote is a strange choice Per Cederqvist
  2025-07-04  4:51 ` Junio C Hamano
@ 2025-07-05 16:57 ` Jeff King
  2025-07-05 18:58   ` [PATCH] remote: detect collisions in remote names Jeff King
  1 sibling, 1 reply; 18+ messages in thread
From: Jeff King @ 2025-07-05 16:57 UTC (permalink / raw)
  To: Per Cederqvist; +Cc: git

On Thu, Jul 03, 2025 at 09:33:20PM +0200, Per Cederqvist wrote:

> > $ git fetch --all
> > Fetching origin
> > From $PRIVATE_URL
> >  + 4e31956300f...30e26ebbb19 chat/master -> origin/chat/master  (forced update)
> > Fetching origin/chat
> > From  $PRIVATE_URL
> >  + 30e26ebbb19...4e31956300f master     -> origin/chat/master  (forced update)
> 
> Every time I run "git fetch --all" git updates the origin/chat/master ref twice.
> 
> If it was up to me, I'd add a check to valid_remote_name() to ensure
> the name doesn't contain any "/" character.  I doubt it is used often.

I think the "/" here is really just a special case of a more general
problem: overlapping fetch refspec destinations.

For example, try this:

  git init repo
  cd repo

  git init one
  git -C one commit --allow-empty -m foo

  git init two
  git -C two commit --allow-empty -m bar

  git config remote.one.url one
  git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
  git config remote.two.url two
  git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*

  git fetch --all

which gives similar output to what you showed above. Of course it's
easier to see here when the names are identical rather than one being a
prefix of the other. But it's fundamentally the same issue, and
forbidding "/" would not fix it.

We could perhaps detect these kinds of overlap, but I wonder:

  1. How expensive is it to do so, and when should we do it? Obviously
     for a handful of refs a quadratic approach is OK. But what if you
     had 10,000 remotes (this is not purely hypothetical; GitHub used to
     manage object migration in its fork networks with configured
     remotes, but hit enough performance issues to switch away from
     that). So I'd be hesitant to check this on every "git fetch".

  2. Is it something people actually want to do? It's certainly a
     _weird_ configuration, but I could imagine there being useful
     corner cases (e.g., one URL is an infrequently backup of the other,
     so you don't usually do "--all", or you set skipDefaultUpdate for
     one of them.

So I dunno. It feels like a configuration error in most cases, but not
all. I'd probably say that people touching the config manually should be
allowed to do what they want, but maybe "git remote" should be a bit
more careful about names being proper subsets of existing remotes (it
should already prevent the exact-match above, I'd think, because the ref
namespace it uses will always match the configuration name).

-Peff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] remote: detect collisions in remote names
  2025-07-05 16:57 ` Jeff King
@ 2025-07-05 18:58   ` Jeff King
  2025-07-07  9:14     ` Patrick Steinhardt
                       ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Jeff King @ 2025-07-05 18:58 UTC (permalink / raw)
  To: Per Cederqvist; +Cc: git

On Sat, Jul 05, 2025 at 12:57:50PM -0400, Jeff King wrote:

> So I dunno. It feels like a configuration error in most cases, but not
> all. I'd probably say that people touching the config manually should be
> allowed to do what they want, but maybe "git remote" should be a bit
> more careful about names being proper subsets of existing remotes (it
> should already prevent the exact-match above, I'd think, because the ref
> namespace it uses will always match the configuration name).

So I'm not entirely convinced we should do anything here. The answer
might just be "if it hurts, don't do it". But if we wanted any
protections in the "git remote" porcelain, they might look like this:

-- >8 --
Subject: [PATCH] remote: detect collisions in remote names

When two remotes collide in the destinations of their fetch refspecs,
the results can be confusing. For example, in this silly example:

  git config remote.one.url [...]
  git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
  git config remote.two.url [...]
  git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
  git fetch --all

we may try to write to the same ref twice (once for each remote we're
fetching). There's also a more subtle version of this. If you have
remotes "outer/inner" and "outer", then the ref "inner/branch" on the
second remote will conflict with just "branch" on the former (they both
want to write to "refs/remotes/outer/inner/branch").

We probably don't want to forbid this kind of overlap completely. While
the results can be confusing, there are legitimate reasons to have
multiple refs write into the same namespace (e.g., if one is a "backup"
of the other that is rarely fetched from).

But it may be worth limiting the porcelain "git remote" command to avoid
this confusion. The example above cannot be done with "git remote",
because it always[1] matches the refspecs to the remote name, and you
can only have one instance of each remote name. But you can still
trigger the more subtle variant like this:

  git remote add outer [...]
  git remote add outer/inner [...]

So let's detect that kind of name collision (in both directions) and
forbid it. You can still do whatever you like by manipulating the config
directly, but this should prevent the most obvious foot-gun.

[1] Almost always. With the --mirror option, the resulting refspec will
    just write into "refs/*"; the remote name does not appear in the ref
    namespace at all.

    Our new "names must not overlap" rule is not necessary for that
    case, but it seems reasonable to enforce it consistently. We already
    require all remote names to be valid in the ref namespace, even
    though we won't ever use them in that context for --mirror remotes.

    Likewise, our new rule doesn't help with overlap here. Any two
    mirror remotes will always overlap (in fact, any mirror remote along
    with any other single one, since refs/remotes/ is a subset of the
    mirrored refs). I'm not sure this is worth worrying about, but if it
    is, we'd want an additional rule like "mirror remotes must be the
    only remote".

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/remote.c  | 17 +++++++++++++++++
 t/t5505-remote.sh | 14 ++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/builtin/remote.c b/builtin/remote.c
index 0d6755bcb7..b18730ddb2 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -157,6 +157,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
 	return 0;
 }
 
+static int check_remote_collision(struct remote *remote, void *vname)
+{
+	const char *name = vname;
+	const char *p;
+
+	if (skip_prefix(name, remote->name, &p) && *p == '/')
+		die(_("remote name '%s' is a subset of existing remote '%s'"),
+		    name, remote->name);
+	if (skip_prefix(remote->name, name, &p) && *p == '/')
+		die(_("remote name '%s' is a superset of existing remote '%s'"),
+		    name, remote->name);
+
+	return 0;
+}
+
 static int add(int argc, const char **argv, const char *prefix,
 	       struct repository *repo UNUSED)
 {
@@ -208,6 +223,8 @@ static int add(int argc, const char **argv, const char *prefix,
 	if (!valid_remote_name(name))
 		die(_("'%s' is not a valid remote name"), name);
 
+	for_each_remote(check_remote_collision, (void *)name);
+
 	strbuf_addf(&buf, "remote.%s.url", name);
 	git_config_set(buf.buf, url);
 
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index bef0250e89..2701eef85e 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1644,4 +1644,18 @@ test_expect_success 'empty config clears remote.*.pushurl list' '
 	test_cmp expect actual
 '
 
+test_expect_success 'forbid adding subset of existing remote' '
+	test_when_finished "git remote rm outer" &&
+	git remote add outer url &&
+	test_must_fail git remote add outer/inner url 2>err &&
+	test_grep ".outer/inner. is a subset of existing remote .outer." err
+'
+
+test_expect_success 'forbid adding superset of existing remote' '
+	test_when_finished "git remote rm outer/inner" &&
+	git remote add outer/inner url &&
+	test_must_fail git remote add outer url 2>err &&
+	test_grep ".outer. is a superset of existing remote .outer/inner." err
+'
+
 test_done
-- 
2.50.0.438.g3b3bebd3e8


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-05 18:58   ` [PATCH] remote: detect collisions in remote names Jeff King
@ 2025-07-07  9:14     ` Patrick Steinhardt
  2025-07-07 20:28       ` Jeff King
  2025-07-07 13:59     ` Junio C Hamano
  2025-07-09 11:56     ` Raymond E. Pasco
  2 siblings, 1 reply; 18+ messages in thread
From: Patrick Steinhardt @ 2025-07-07  9:14 UTC (permalink / raw)
  To: Jeff King; +Cc: Per Cederqvist, git

On Sat, Jul 05, 2025 at 02:58:42PM -0400, Jeff King wrote:
> On Sat, Jul 05, 2025 at 12:57:50PM -0400, Jeff King wrote:
> 
> > So I dunno. It feels like a configuration error in most cases, but not
> > all. I'd probably say that people touching the config manually should be
> > allowed to do what they want, but maybe "git remote" should be a bit
> > more careful about names being proper subsets of existing remotes (it
> > should already prevent the exact-match above, I'd think, because the ref
> > namespace it uses will always match the configuration name).
> 
> So I'm not entirely convinced we should do anything here. The answer
> might just be "if it hurts, don't do it". But if we wanted any
> protections in the "git remote" porcelain, they might look like this:

I think having these protections is sensible. And I also agree with you
that we shouldn't keep people from doing weird things by manipulating
the config directly.

> diff --git a/builtin/remote.c b/builtin/remote.c
> index 0d6755bcb7..b18730ddb2 100644
> --- a/builtin/remote.c
> +++ b/builtin/remote.c
> @@ -157,6 +157,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
>  	return 0;
>  }
>  
> +static int check_remote_collision(struct remote *remote, void *vname)

Tiniest nit: I was a bit puzzled what the `v` in `vname` stands for, and
it took a while until I noticed that it probably stands for `void`. If
you end up rerolling, I'd suggest to either call this `payload` or
`_name`.

> +{
> +	const char *name = vname;
> +	const char *p;
> +
> +	if (skip_prefix(name, remote->name, &p) && *p == '/')
> +		die(_("remote name '%s' is a subset of existing remote '%s'"),
> +		    name, remote->name);
> +	if (skip_prefix(remote->name, name, &p) && *p == '/')
> +		die(_("remote name '%s' is a superset of existing remote '%s'"),
> +		    name, remote->name);
> +
> +	return 0;
> +}
> +

Hm. Do we have to care about '\' on Windows, as well? This made me
rediscover the following function:

    static int valid_remote_nick(const char *name)
    {
    	if (!name[0] || is_dot_or_dotdot(name))
    		return 0;
    
    	/* remote nicknames cannot contain slashes */
    	while (*name)
    		if (is_dir_sep(*name++))
    			return 0;
    	return 1;
    }

Which... puzzled me a bit at first, as it seems to indicate that a
remote with a path separator is invalid. But as it turns out we only use
this function if remotes are configured via ".git/remotes" or
".git/branches". Looks like we eventually lost this limitation, probably
when config-based remotes were introduced.

> @@ -208,6 +223,8 @@ static int add(int argc, const char **argv, const char *prefix,
>  	if (!valid_remote_name(name))
>  		die(_("'%s' is not a valid remote name"), name);
>  
> +	for_each_remote(check_remote_collision, (void *)name);
> +
>  	strbuf_addf(&buf, "remote.%s.url", name);
>  	git_config_set(buf.buf, url);
>  

Nice and simple.

Patrick

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-05 18:58   ` [PATCH] remote: detect collisions in remote names Jeff King
  2025-07-07  9:14     ` Patrick Steinhardt
@ 2025-07-07 13:59     ` Junio C Hamano
  2025-07-09 11:56     ` Raymond E. Pasco
  2 siblings, 0 replies; 18+ messages in thread
From: Junio C Hamano @ 2025-07-07 13:59 UTC (permalink / raw)
  To: Jeff King; +Cc: Per Cederqvist, git

Jeff King <peff@peff.net> writes:

> On Sat, Jul 05, 2025 at 12:57:50PM -0400, Jeff King wrote:
>
>> So I dunno. It feels like a configuration error in most cases, but not
>> all. I'd probably say that people touching the config manually should be
>> allowed to do what they want, but maybe "git remote" should be a bit
>> more careful about names being proper subsets of existing remotes (it
>> should already prevent the exact-match above, I'd think, because the ref
>> namespace it uses will always match the configuration name).
>
> So I'm not entirely convinced we should do anything here. The answer
> might just be "if it hurts, don't do it". But if we wanted any
> protections in the "git remote" porcelain, they might look like this:

I have firmly been in the "if it hurts..." camp.  People can do
weird things that may not make much sense to me, but do make sense
in their workflow that may be vastly different from mine.

But I do not think of any downsides from forbidding outer and
outer/inner existing at the same time, either ;-).

Thanks.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-07  9:14     ` Patrick Steinhardt
@ 2025-07-07 20:28       ` Jeff King
  2025-07-07 21:04         ` Junio C Hamano
  0 siblings, 1 reply; 18+ messages in thread
From: Jeff King @ 2025-07-07 20:28 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: Per Cederqvist, git

On Mon, Jul 07, 2025 at 11:14:05AM +0200, Patrick Steinhardt wrote:

> > +static int check_remote_collision(struct remote *remote, void *vname)
> 
> Tiniest nit: I was a bit puzzled what the `v` in `vname` stands for, and
> it took a while until I noticed that it probably stands for `void`. If
> you end up rerolling, I'd suggest to either call this `payload` or
> `_name`.

Yeah, it's for "void". This is a pattern used elsewhere for callbacks
(usually as "vdata", but here we didn't need a container struct since
there's only one item). I think "payload" is not a term we usually use,
but maybe just "data" would be the usual thing (we only need "vdata"
when we're assigning to the non-void data type).

IMHO we should probably avoid the underscore pattern. It's OK here, but
it runs close to violating the reserved names rules (a global variable
variable _name is bad, and _Name anywhere is bad).

> Hm. Do we have to care about '\' on Windows, as well? This made me
> rediscover the following function:
> 
>     static int valid_remote_nick(const char *name)
>     {
>     	if (!name[0] || is_dot_or_dotdot(name))
>     		return 0;
>     
>     	/* remote nicknames cannot contain slashes */
>     	while (*name)
>     		if (is_dir_sep(*name++))
>     			return 0;
>     	return 1;
>     }
> 
> Which... puzzled me a bit at first, as it seems to indicate that a
> remote with a path separator is invalid. But as it turns out we only use
> this function if remotes are configured via ".git/remotes" or
> ".git/branches". Looks like we eventually lost this limitation, probably
> when config-based remotes were introduced.

AFAICT "remote add" allows anything that parses as a refspec, which
implies that refs/remotes/<name>/ passes check_refname_format(). And we
don't allow backslashes there:

  $ git remote add foo/bar url
  [no output, $? is 0]
  $ git remote add 'bar\foo' url
  fatal: 'bar\foo' is not a valid remote name

I don't think this is platform dependent. It's coming from the
refname_disposition table, so we're not calling is_dir_sep(). Only '/'
is marked in that table as end-of-component, and "\\" is forbidden.

So I don't think we need to worry about backslashes here.

-Peff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-07 20:28       ` Jeff King
@ 2025-07-07 21:04         ` Junio C Hamano
  2025-07-08 22:59           ` Jeff King
  0 siblings, 1 reply; 18+ messages in thread
From: Junio C Hamano @ 2025-07-07 21:04 UTC (permalink / raw)
  To: Jeff King; +Cc: Patrick Steinhardt, Per Cederqvist, git

Jeff King <peff@peff.net> writes:

> On Mon, Jul 07, 2025 at 11:14:05AM +0200, Patrick Steinhardt wrote:
>
>> > +static int check_remote_collision(struct remote *remote, void *vname)
>> 
>> Tiniest nit: I was a bit puzzled what the `v` in `vname` stands for, and
>> it took a while until I noticed that it probably stands for `void`. If
>> you end up rerolling, I'd suggest to either call this `payload` or
>> `_name`.
>
> Yeah, it's for "void". This is a pattern used elsewhere for callbacks
> (usually as "vdata", but here we didn't need a container struct since
> there's only one item). I think "payload" is not a term we usually use,
> but maybe just "data" would be the usual thing (we only need "vdata"
> when we're assigning to the non-void data type).
>
> IMHO we should probably avoid the underscore pattern. It's OK here, but
> it runs close to violating the reserved names rules (a global variable
> variable _name is bad, and _Name anywhere is bad).

"name_" is available.  In fact I think it is a very common pattern
in this codebase to name an incoming parameter with trailing "_",
and assign it to a local variable with the right name and with the
right type at the top of the function.

> AFAICT "remote add" allows anything that parses as a refspec, which
> implies that refs/remotes/<name>/ passes check_refname_format(). And we
> don't allow backslashes there:
>
>   $ git remote add foo/bar url
>   [no output, $? is 0]
>   $ git remote add 'bar\foo' url
>   fatal: 'bar\foo' is not a valid remote name
>
> I don't think this is platform dependent. It's coming from the
> refname_disposition table, so we're not calling is_dir_sep(). Only '/'
> is marked in that table as end-of-component, and "\\" is forbidden.
>
> So I don't think we need to worry about backslashes here.

That agrees with my understanding.  Thanks for carefully checking.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-07 21:04         ` Junio C Hamano
@ 2025-07-08 22:59           ` Jeff King
  2025-07-08 23:02             ` Jeff King
  2025-07-08 23:28             ` Junio C Hamano
  0 siblings, 2 replies; 18+ messages in thread
From: Jeff King @ 2025-07-08 22:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Patrick Steinhardt, Per Cederqvist, git

On Mon, Jul 07, 2025 at 02:04:19PM -0700, Junio C Hamano wrote:

> > IMHO we should probably avoid the underscore pattern. It's OK here, but
> > it runs close to violating the reserved names rules (a global variable
> > variable _name is bad, and _Name anywhere is bad).
> 
> "name_" is available.  In fact I think it is a very common pattern
> in this codebase to name an incoming parameter with trailing "_",
> and assign it to a local variable with the right name and with the
> right type at the top of the function.

Yeah, that is legal and is a pattern we use (though I admit that I find
any underscores kind of ugly and easy to miss). I was curious how often
each pattern appeared:

  ["v" prefix: vdata, va, etc]
  $ git grep 'void \*v' '*.c' | wc -l
  51

  [leading underscore: _data, _a, etc]
  $ git grep 'void \*_' '*.c' | wc -l
  52

  [trailing underscore: mostly a_, b_ in comparators]
  $ git grep 'void \*[a-zA-Z0-9]_' '*.c'  | wc -l
  30

  [just calling it "data"]
  $ git grep 'void \*data' '*.c' | wc -l
  314

The last one is cheating a little because it catches function pointer
declarations, too, but grepping for "= data;" returns over a hundred
hits, too.

So that was mostly for fun, and I think any is OK. ;) But here is the
patch again with the void pointer just called "data".

Although I think we're all a bit lukewarm on the concept, I feel like it
won't hurt anything, isn't too much code, and disables a potential (if
somewhat rare) footgun. So probably worth doing?

-- >8 --
Subject: [PATCH] remote: detect collisions in remote names

When two remotes collide in the destinations of their fetch refspecs,
the results can be confusing. For example, in this silly example:

  git config remote.one.url [...]
  git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
  git config remote.two.url [...]
  git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
  git fetch --all

we may try to write to the same ref twice (once for each remote we're
fetching). There's also a more subtle version of this. If you have
remotes "outer/inner" and "outer", then the ref "inner/branch" on the
second remote will conflict with just "branch" on the former (they both
want to write to "refs/remotes/outer/inner/branch").

We probably don't want to forbid this kind of overlap completely. While
the results can be confusing, there are legitimate reasons to have
multiple refs write into the same namespace (e.g., if one is a "backup"
of the other that is rarely fetched from).

But it may be worth limiting the porcelain "git remote" command to avoid
this confusion. The example above cannot be done with "git remote",
because it always[1] matches the refspecs to the remote name, and you
can only have one instance of each remote name. But you can still
trigger the more subtle variant like this:

  git remote add outer [...]
  git remote add outer/inner [...]

So let's detect that kind of name collision (in both directions) and
forbid it. You can still do whatever you like by manipulating the config
directly, but this should prevent the most obvious foot-gun.

[1] Almost always. With the --mirror option, the resulting refspec will
    just write into "refs/*"; the remote name does not appear in the ref
    namespace at all.

    Our new "names must not overlap" rule is not necessary for that
    case, but it seems reasonable to enforce it consistently. We already
    require all remote names to be valid in the ref namespace, even
    though we won't ever use them in that context for --mirror remotes.

    Likewise, our new rule doesn't help with overlap here. Any two
    mirror remotes will always overlap (in fact, any mirror remote along
    with any other single one, since refs/remotes/ is a subset of the
    mirrored refs). I'm not sure this is worth worrying about, but if it
    is, we'd want an additional rule like "mirror remotes must be the
    only remote".

Signed-off-by: Jeff King <peff@peff.net>
---
Subject: [PATCH] remote: detect collisions in remote names

When two remotes collide in the destinations of their fetch refspecs,
the results can be confusing. For example, in this silly example:

  git config remote.one.url [...]
  git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
  git config remote.two.url [...]
  git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
  git fetch --all

we may try to write to the same ref twice (once for each remote we're
fetching). There's also a more subtle version of this. If you have
remotes "outer/inner" and "outer", then the ref "inner/branch" on the
second remote will conflict with just "branch" on the former (they both
want to write to "refs/remotes/outer/inner/branch").

We probably don't want to forbid this kind of overlap completely. While
the results can be confusing, there are legitimate reasons to have
multiple refs write into the same namespace (e.g., if one is a "backup"
of the other that is rarely fetched from).

But it may be worth limiting the porcelain "git remote" command to avoid
this confusion. The example above cannot be done with "git remote",
because it always[1] matches the refspecs to the remote name, and you
can only have one instance of each remote name. But you can still
trigger the more subtle variant like this:

  git remote add outer [...]
  git remote add outer/inner [...]

So let's detect that kind of name collision (in both directions) and
forbid it. You can still do whatever you like by manipulating the config
directly, but this should prevent the most obvious foot-gun.

[1] Almost always. With the --mirror option, the resulting refspec will
    just write into "refs/*"; the remote name does not appear in the ref
    namespace at all.

    Our new "names must not overlap" rule is not necessary for that
    case, but it seems reasonable to enforce it consistently. We already
    require all remote names to be valid in the ref namespace, even
    though we won't ever use them in that context for --mirror remotes.

    Likewise, our new rule doesn't help with overlap here. Any two
    mirror remotes will always overlap (in fact, any mirror remote along
    with any other single one, since refs/remotes/ is a subset of the
    mirrored refs). I'm not sure this is worth worrying about, but if it
    is, we'd want an additional rule like "mirror remotes must be the
    only remote".

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/remote.c  | 17 +++++++++++++++++
 t/t5505-remote.sh | 14 ++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/builtin/remote.c b/builtin/remote.c
index 0d6755bcb7..a770df669c 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -157,6 +157,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
 	return 0;
 }
 
+static int check_remote_collision(struct remote *remote, void *data)
+{
+	const char *name = data;
+	const char *p;
+
+	if (skip_prefix(name, remote->name, &p) && *p == '/')
+		die(_("remote name '%s' is a subset of existing remote '%s'"),
+		    name, remote->name);
+	if (skip_prefix(remote->name, name, &p) && *p == '/')
+		die(_("remote name '%s' is a superset of existing remote '%s'"),
+		    name, remote->name);
+
+	return 0;
+}
+
 static int add(int argc, const char **argv, const char *prefix,
 	       struct repository *repo UNUSED)
 {
@@ -208,6 +223,8 @@ static int add(int argc, const char **argv, const char *prefix,
 	if (!valid_remote_name(name))
 		die(_("'%s' is not a valid remote name"), name);
 
+	for_each_remote(check_remote_collision, (void *)name);
+
 	strbuf_addf(&buf, "remote.%s.url", name);
 	git_config_set(buf.buf, url);
 
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index bef0250e89..2701eef85e 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1644,4 +1644,18 @@ test_expect_success 'empty config clears remote.*.pushurl list' '
 	test_cmp expect actual
 '
 
+test_expect_success 'forbid adding subset of existing remote' '
+	test_when_finished "git remote rm outer" &&
+	git remote add outer url &&
+	test_must_fail git remote add outer/inner url 2>err &&
+	test_grep ".outer/inner. is a subset of existing remote .outer." err
+'
+
+test_expect_success 'forbid adding superset of existing remote' '
+	test_when_finished "git remote rm outer/inner" &&
+	git remote add outer/inner url &&
+	test_must_fail git remote add outer url 2>err &&
+	test_grep ".outer. is a superset of existing remote .outer/inner." err
+'
+
 test_done
-- 
2.50.1.488.g2a977559af


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-08 22:59           ` Jeff King
@ 2025-07-08 23:02             ` Jeff King
  2025-07-08 23:28             ` Junio C Hamano
  1 sibling, 0 replies; 18+ messages in thread
From: Jeff King @ 2025-07-08 23:02 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Patrick Steinhardt, Per Cederqvist, git

On Tue, Jul 08, 2025 at 06:59:47PM -0400, Jeff King wrote:

> Although I think we're all a bit lukewarm on the concept, I feel like it
> won't hurt anything, isn't too much code, and disables a potential (if
> somewhat rare) footgun. So probably worth doing?

> -- >8 --
> Subject: [PATCH] remote: detect collisions in remote names
> [...]
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> Subject: [PATCH] remote: detect collisions in remote names

Sorry, I am apparently bad at using my editor.

I _think_ this will just apply correctly for you, since the duplicated
commit message is all after the "---".

-Peff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-08 22:59           ` Jeff King
  2025-07-08 23:02             ` Jeff King
@ 2025-07-08 23:28             ` Junio C Hamano
  2025-07-09  1:21               ` Jeff King
  1 sibling, 1 reply; 18+ messages in thread
From: Junio C Hamano @ 2025-07-08 23:28 UTC (permalink / raw)
  To: Jeff King; +Cc: Patrick Steinhardt, Per Cederqvist, git

Jeff King <peff@peff.net> writes:

> On Mon, Jul 07, 2025 at 02:04:19PM -0700, Junio C Hamano wrote:
>
>> > IMHO we should probably avoid the underscore pattern. It's OK here, but
>> > it runs close to violating the reserved names rules (a global variable
>> > variable _name is bad, and _Name anywhere is bad).
>> 
>> "name_" is available.  In fact I think it is a very common pattern
>> in this codebase to name an incoming parameter with trailing "_",
>> and assign it to a local variable with the right name and with the
>> right type at the top of the function.
>
> Yeah, that is legal and is a pattern we use (though I admit that I find
> any underscores kind of ugly and easy to miss). I was curious how often
> each pattern appeared:
>
>   ["v" prefix: vdata, va, etc]
>   $ git grep 'void \*v' '*.c' | wc -l
>   51
>
>   [leading underscore: _data, _a, etc]
>   $ git grep 'void \*_' '*.c' | wc -l
>   52
>
>   [trailing underscore: mostly a_, b_ in comparators]
>   $ git grep 'void \*[a-zA-Z0-9]_' '*.c'  | wc -l
>   30

Only a single letter followed by an underscore, which may be
followed by more letters legal in names (like a_bcde)?

A more fair pattern may be something like

$ git grep 'void \*[A-Za-z_0-9]*_[^A-Za-z_0-9]' \*.c | wc -l
52

>   [just calling it "data"]
>   $ git grep 'void \*data' '*.c' | wc -l
>   314
>
> The last one is cheating a little because it catches function pointer
> declarations, too, but grepping for "= data;" returns over a hundred
> hits, too.

Also "void *cb_data" is fairly common, I think, as we have some
callback API functions.

$ git grep 'void \*cb_data' \*.c | wc -l
234

> So that was mostly for fun, and I think any is OK. ;) But here is the
> patch again with the void pointer just called "data".

Yeah, I think any would be fine.  I was a bit surprised that
v-something was so widely used, though, as I find that it makes the
least sense among all possibilities (and "data" is the distant
second, as it would become awkward when you have to have more than
one, like my_custom_cmp(void *left, void *right), if your rule says
that you must say "data").

> Although I think we're all a bit lukewarm on the concept, I feel like it
> won't hurt anything, isn't too much code, and disables a potential (if
> somewhat rare) footgun. So probably worth doing?

Even though it does not cover all cases, at least those coming from
"git remote" will be able to avoid surprises, so let me replace with
this version, wait for a few days for more inputs from others and
then mark it for 'next' if nobody sees any downsides.


> -- >8 --
> Subject: [PATCH] remote: detect collisions in remote names
>
> When two remotes collide in the destinations of their fetch refspecs,
> the results can be confusing. For example, in this silly example:
>
>   git config remote.one.url [...]
>   git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
>   git config remote.two.url [...]
>   git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
>   git fetch --all
>
> we may try to write to the same ref twice (once for each remote we're
> fetching). There's also a more subtle version of this. If you have
> remotes "outer/inner" and "outer", then the ref "inner/branch" on the
> second remote will conflict with just "branch" on the former (they both
> want to write to "refs/remotes/outer/inner/branch").
>
> We probably don't want to forbid this kind of overlap completely. While
> the results can be confusing, there are legitimate reasons to have
> multiple refs write into the same namespace (e.g., if one is a "backup"
> of the other that is rarely fetched from).
>
> But it may be worth limiting the porcelain "git remote" command to avoid
> this confusion. The example above cannot be done with "git remote",
> because it always[1] matches the refspecs to the remote name, and you
> can only have one instance of each remote name. But you can still
> trigger the more subtle variant like this:
>
>   git remote add outer [...]
>   git remote add outer/inner [...]
>
> So let's detect that kind of name collision (in both directions) and
> forbid it. You can still do whatever you like by manipulating the config
> directly, but this should prevent the most obvious foot-gun.
>
> [1] Almost always. With the --mirror option, the resulting refspec will
>     just write into "refs/*"; the remote name does not appear in the ref
>     namespace at all.
>
>     Our new "names must not overlap" rule is not necessary for that
>     case, but it seems reasonable to enforce it consistently. We already
>     require all remote names to be valid in the ref namespace, even
>     though we won't ever use them in that context for --mirror remotes.
>
>     Likewise, our new rule doesn't help with overlap here. Any two
>     mirror remotes will always overlap (in fact, any mirror remote along
>     with any other single one, since refs/remotes/ is a subset of the
>     mirrored refs). I'm not sure this is worth worrying about, but if it
>     is, we'd want an additional rule like "mirror remotes must be the
>     only remote".
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> Subject: [PATCH] remote: detect collisions in remote names
>
> When two remotes collide in the destinations of their fetch refspecs,
> the results can be confusing. For example, in this silly example:
>
>   git config remote.one.url [...]
>   git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
>   git config remote.two.url [...]
>   git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
>   git fetch --all
>
> we may try to write to the same ref twice (once for each remote we're
> fetching). There's also a more subtle version of this. If you have
> remotes "outer/inner" and "outer", then the ref "inner/branch" on the
> second remote will conflict with just "branch" on the former (they both
> want to write to "refs/remotes/outer/inner/branch").
>
> We probably don't want to forbid this kind of overlap completely. While
> the results can be confusing, there are legitimate reasons to have
> multiple refs write into the same namespace (e.g., if one is a "backup"
> of the other that is rarely fetched from).
>
> But it may be worth limiting the porcelain "git remote" command to avoid
> this confusion. The example above cannot be done with "git remote",
> because it always[1] matches the refspecs to the remote name, and you
> can only have one instance of each remote name. But you can still
> trigger the more subtle variant like this:
>
>   git remote add outer [...]
>   git remote add outer/inner [...]
>
> So let's detect that kind of name collision (in both directions) and
> forbid it. You can still do whatever you like by manipulating the config
> directly, but this should prevent the most obvious foot-gun.
>
> [1] Almost always. With the --mirror option, the resulting refspec will
>     just write into "refs/*"; the remote name does not appear in the ref
>     namespace at all.
>
>     Our new "names must not overlap" rule is not necessary for that
>     case, but it seems reasonable to enforce it consistently. We already
>     require all remote names to be valid in the ref namespace, even
>     though we won't ever use them in that context for --mirror remotes.
>
>     Likewise, our new rule doesn't help with overlap here. Any two
>     mirror remotes will always overlap (in fact, any mirror remote along
>     with any other single one, since refs/remotes/ is a subset of the
>     mirrored refs). I'm not sure this is worth worrying about, but if it
>     is, we'd want an additional rule like "mirror remotes must be the
>     only remote".
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/remote.c  | 17 +++++++++++++++++
>  t/t5505-remote.sh | 14 ++++++++++++++
>  2 files changed, 31 insertions(+)
>
> diff --git a/builtin/remote.c b/builtin/remote.c
> index 0d6755bcb7..a770df669c 100644
> --- a/builtin/remote.c
> +++ b/builtin/remote.c
> @@ -157,6 +157,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
>  	return 0;
>  }
>  
> +static int check_remote_collision(struct remote *remote, void *data)
> +{
> +	const char *name = data;
> +	const char *p;
> +
> +	if (skip_prefix(name, remote->name, &p) && *p == '/')
> +		die(_("remote name '%s' is a subset of existing remote '%s'"),
> +		    name, remote->name);
> +	if (skip_prefix(remote->name, name, &p) && *p == '/')
> +		die(_("remote name '%s' is a superset of existing remote '%s'"),
> +		    name, remote->name);
> +
> +	return 0;
> +}
> +
>  static int add(int argc, const char **argv, const char *prefix,
>  	       struct repository *repo UNUSED)
>  {
> @@ -208,6 +223,8 @@ static int add(int argc, const char **argv, const char *prefix,
>  	if (!valid_remote_name(name))
>  		die(_("'%s' is not a valid remote name"), name);
>  
> +	for_each_remote(check_remote_collision, (void *)name);
> +
>  	strbuf_addf(&buf, "remote.%s.url", name);
>  	git_config_set(buf.buf, url);
>  
> diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
> index bef0250e89..2701eef85e 100755
> --- a/t/t5505-remote.sh
> +++ b/t/t5505-remote.sh
> @@ -1644,4 +1644,18 @@ test_expect_success 'empty config clears remote.*.pushurl list' '
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'forbid adding subset of existing remote' '
> +	test_when_finished "git remote rm outer" &&
> +	git remote add outer url &&
> +	test_must_fail git remote add outer/inner url 2>err &&
> +	test_grep ".outer/inner. is a subset of existing remote .outer." err
> +'
> +
> +test_expect_success 'forbid adding superset of existing remote' '
> +	test_when_finished "git remote rm outer/inner" &&
> +	git remote add outer/inner url &&
> +	test_must_fail git remote add outer url 2>err &&
> +	test_grep ".outer. is a superset of existing remote .outer/inner." err
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-08 23:28             ` Junio C Hamano
@ 2025-07-09  1:21               ` Jeff King
  0 siblings, 0 replies; 18+ messages in thread
From: Jeff King @ 2025-07-09  1:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Patrick Steinhardt, Per Cederqvist, git

On Tue, Jul 08, 2025 at 04:28:43PM -0700, Junio C Hamano wrote:

> >   [trailing underscore: mostly a_, b_ in comparators]
> >   $ git grep 'void \*[a-zA-Z0-9]_' '*.c'  | wc -l
> >   30
> 
> Only a single letter followed by an underscore, which may be
> followed by more letters legal in names (like a_bcde)?
> 
> A more fair pattern may be something like
> 
> $ git grep 'void \*[A-Za-z_0-9]*_[^A-Za-z_0-9]' \*.c | wc -l
> 52

Doh, yeah. No wonder it mostly found "a_" and "b_". ;) Yours is a much
better pattern.

> > Although I think we're all a bit lukewarm on the concept, I feel like it
> > won't hurt anything, isn't too much code, and disables a potential (if
> > somewhat rare) footgun. So probably worth doing?
> 
> Even though it does not cover all cases, at least those coming from
> "git remote" will be able to avoid surprises, so let me replace with
> this version, wait for a few days for more inputs from others and
> then mark it for 'next' if nobody sees any downsides.

Sounds good, thanks.

-Peff

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] remote: detect collisions in remote names
  2025-07-05 18:58   ` [PATCH] remote: detect collisions in remote names Jeff King
  2025-07-07  9:14     ` Patrick Steinhardt
  2025-07-07 13:59     ` Junio C Hamano
@ 2025-07-09 11:56     ` Raymond E. Pasco
  2 siblings, 0 replies; 18+ messages in thread
From: Raymond E. Pasco @ 2025-07-09 11:56 UTC (permalink / raw)
  To: Jeff King; +Cc: Per Cederqvist, git

On 25/07/05 02:58PM, Jeff King wrote:
> When two remotes collide in the destinations of their fetch refspecs,
> the results can be confusing. For example, in this silly example:
> 
>   git config remote.one.url [...]
>   git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
>   git config remote.two.url [...]
>   git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
>   git fetch --all
> 
> we may try to write to the same ref twice (once for each remote we're
> fetching). There's also a more subtle version of this. If you have
> remotes "outer/inner" and "outer", then the ref "inner/branch" on the
> second remote will conflict with just "branch" on the former (they both
> want to write to "refs/remotes/outer/inner/branch").

I can give my thoughts from the perspective of someone with an affected
workflow, if no one else is doing that.

I would expect '/' in remote names to be fairly common among people who
name remotes at all (a minority compared to those who have one remote
autonamed 'origin', probably); many things, from kernel.org to Github,
use path-like names (often username/reponame) to name repositories,
and the most relevant subset of that path is a natural thing to name a
remote. But that part doesn't seem controversial, despite the initial
message in this thread. So that's not a problem for me.

What this patch disallows, at least in porcelain, is something like
(these names are just examples) my naming a remote for gregkh/linux.git
"gregkh" and also naming a remote for gregkh/scsi.git "gregkh/scsi",
because it might lead to colliding names if gregkh makes a branch named
"scsi" on the former.

I've probably ever named remotes like this before, though I don't see
any examples in repositories I'm actively using this week. It's
plausible that other people have done this, or are doing it, though if I
had ever shot myself in the foot doing so I would have stopped.

Because it does seem prone to annoying mishaps, I think a change like
this is probably a good idea. It's not a confusing concept, because it's
familiar from how branch names with '/' in them already work.

What would the 'git remote' porcelain do in cases where remotes like
this already exist? I think, from this patch, nothing, since it's
only changing add()?

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2025-07-09 11:56 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-03 19:33 Allowing "/" in the name of a git remote is a strange choice Per Cederqvist
2025-07-04  4:51 ` Junio C Hamano
2025-07-04  5:13   ` Patrick Steinhardt
2025-07-04  8:10     ` Lidong Yan
2025-07-04  8:17     ` Lidong Yan
2025-07-04 14:18     ` Junio C Hamano
2025-07-04  6:42   ` Per Cederqvist
2025-07-05 16:57 ` Jeff King
2025-07-05 18:58   ` [PATCH] remote: detect collisions in remote names Jeff King
2025-07-07  9:14     ` Patrick Steinhardt
2025-07-07 20:28       ` Jeff King
2025-07-07 21:04         ` Junio C Hamano
2025-07-08 22:59           ` Jeff King
2025-07-08 23:02             ` Jeff King
2025-07-08 23:28             ` Junio C Hamano
2025-07-09  1:21               ` Jeff King
2025-07-07 13:59     ` Junio C Hamano
2025-07-09 11:56     ` Raymond E. Pasco

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).