threads / discuss / 58361

Potential problems with url.<base>.insteadOf

Subject: Potential problems with url.<base>.insteadOf

## tl;dr

5 messages between Aug 25, 2022 and Aug 26, 2022.

replies: 4people: 3as markdown or json

Javier Mora· Aug 25, 2022, 23:47 UTC · lore

The choice of `url.<replacement>.insteadOf <original>` as a way to replace URLs is not only a bit confusing, as it has already been discussed[1], but also presents some problems and makes it impossible to achieve certain configurations. [1] https://public-inbox.org/git/20181122173109.GI28192@sigill.intra.peff.net/

SCENARIO 1: I want to replace all references to the (now defunct) 'http://example.org/' to the new server, 'http://example.com/'.

OK, that is easy (even if a bit counter-intuitive). Just do: git config url.'http://example.com/'.insteadOf 'http://example.org/'

SCENARIO 2: I want to replace BOTH 'http://example.org/' and 'http://example.net/' with 'http://example.com/'.

Well, now I have a problem.  If I do:

git config url.'http://example.com/'.insteadOf 'http://example.org/' git config url.'http://example.com/'.insteadOf 'http://example.net/'

the second entry will replace the first, since I'm just using the config entry `url.http://example.com/.insteadOf` twice. So, it appears that this simply cannot be done in Git! (Maybe if I daisy-chain them? like .org -> .net and then .net -> .com)

SCENARIO 3: I had set 'http://example.org/' to redirect to 'http://example.com/', but that was a mistake, or there has been a migration, and it should be 'http://example.edu/'.

The "natural reaction" here is to rewrite the command with the right replacement value, but if I write:

git config url.'http://example.com/'.insteadOf 'http://example.org/' git config url.'http://example.edu/'.insteadOf 'http://example.org/'

the second command doesn't replace the first, but instead is added alongside. I'll need to manually unset the first:

git config --unset url.'http://example.com/'.insteadOf

SCENARIO 4: For some reason (e.g. because I messed up in scenario 3), there are two insteadOf entries in the git config with the same value. This results in an ambiguous case, and Git does nothing to prevent it! The documentation says that the longest insteadOf value wins, but both have the same length since both are the same URL.

----

SOLUTION: None of this would happen if, instead of a `url.<replacement>.insteadOf <original>` approach, Git followed the opposite approach, `url.<original>.replaceWith <replacement>` (or `rewriteTo`, as it is suggested in [1]). So this approach is not only more intuitive and looks more resilient, it IS more resilient.

Let's have a look at the previous scenarios again:

SCENARIO 1: About as easy as before, except that it follows a more readable "from ... to ..." scheme:

git config url.'http://example.org/'.replaceWith 'http://example.com/'

(which I suspect will also give Git less trouble to find in the config, or at least it feels like it would).

SCENARIO 2: Easy peasy. Two different sources with the same target = two different keys with the same value:

git config url.'http://example.org/'.replaceWith 'http://example.com/' git config url.'http://example.net/'.replaceWith 'http://example.com/'

And we no longer have the problem that we cannot replace two different URLs with the same replacement.

SCENARIO 3: Rewriting the rule will simply overwrite the old value:

git config url.'http://example.org/'.replaceWith 'http://example.com/' git config url.'http://example.org/'.replaceWith 'http://example.edu/'

SCENARIO 4: Scenario 4 simply cannot happen with this approach under normal circumstances because there can't be two entries with the same key but different values, unless the user edited the config file manually. (But there CAN be two entries with different keys and the same value, which is what caused scenario 4 before.)

So, it might be a good idea to implement and recommend the `replaceWith` (or `rewriteTo`) syntax, and deprecate the `insteadOf` syntax (although it'll probably be necessary to keep it around for backwards compatibility).

Andreas Schwab· Aug 26, 2022, 07:09 UTC · re: Javier Mora · lore

Re: Potential problems with url.<base>.insteadOf

On Aug 26 2022, Javier Mora wrote:
> Well, now I have a problem.  If I do:
>
> git config url.'http://example.com/'.insteadOf 'http://example.org/'
> git config url.'http://example.com/'.insteadOf 'http://example.net/'
git config --add url.'http://example.com/'.insteadOf 'http://example.net/'
-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."
Javier Mora· Aug 26, 2022, 09:34 UTC · re: Andreas Schwab · lore

Re: Potential problems with url.<base>.insteadOf

El vie, 26 ago 2022 a las 9:09, Andreas Schwab (<schwab@linux-m68k.org>) escribió:

Show 9 quoted lines
>
> On Aug 26 2022, Javier Mora wrote:
>
> > Well, now I have a problem.  If I do:
> >
> > git config url.'http://example.com/'.insteadOf 'http://example.org/'
> > git config url.'http://example.com/'.insteadOf 'http://example.net/'
>
> git config --add url.'http://example.com/'.insteadOf 'http://example.net/'

Well, that was embarrassing... My bad; I didn't know about the `--add` option (nor that gitconfig supported multi-value options, for that matter, but that's on me for not reading the whole manpage). Maybe the manpage section on `insteadOf` should mention that it's a multi-value option, but I see that this is not a bug as I thought it was. (If anything, a not-very-intuitive feature, but that's a different matter.)

One minor issue I still see is the fact that adding the same insteadOf key-value pair multiple times will result in the same line being added multiple times unless you explicitly delete it first; there doesn't seem to be an easy way to "add key-value pair if it doesn't exist yet". (The closest seems to be `--replace-all`, but that complicates things a bit.)

Junio C Hamano· Aug 26, 2022, 16:13 UTC · re: Javier Mora · lore

Re: Potential problems with url.<base>.insteadOf

Javier Mora <cousteaulecommandant@gmail.com> writes:
Show 16 quoted lines
> The choice of `url.<replacement>.insteadOf <original>` as a way to
> replace URLs is not only a bit confusing, as it has already been
> discussed[1], but also presents some problems and makes it impossible
> to achieve certain configurations.
> [1] https://public-inbox.org/git/20181122173109.GI28192@sigill.intra.peff.net/
>
> SCENARIO 1:
> I want to replace all references to the (now defunct)
> 'http://example.org/' to the new server, 'http://example.com/'.
>
> OK, that is easy (even if a bit counter-intuitive).  Just do:
> git config url.'http://example.com/'.insteadOf 'http://example.org/'
>
> SCENARIO 2:
> I want to replace BOTH 'http://example.org/' and 'http://example.net/'
> with 'http://example.com/'.
So, you want to end up with
    [url "http://example.com/"]
	insteadOf = http://example.org
	insteadOf = http://example.net

but you cannot get there with only "git config VARIABLE VALUE", because that syntax is used to clear the existing values for VARIRABLE before setting it to VALUE.

Have you tried
    $ git config url.http://example.com/.insteadof http://example.org

that clears existing values for url.http://example.com/.insteadof and sets it to "http://example.org", then immediately follow it with

    $ git config --add url.http://example.com/.insteadof http://example.net

that keeps existing values for url.http://example.com/.insteadof and adds another value to the same variable?

Junio C Hamano· Aug 26, 2022, 16:16 UTC · re: Javier Mora · lore

Re: Potential problems with url.<base>.insteadOf

Javier Mora <cousteaulecommandant@gmail.com> writes:
> This results in an ambiguous case, and Git does nothing to prevent it!
> The documentation says that the longest insteadOf value wins, but both
> have the same length since both are the same URL.
The longest has this case in mind:
    [url "A"] insteadof = https://example.com/
    [url "B"] insteadof = https://example.com/special/

So "A" is used as a replacement for the whole site, except for the special hierarchy that is rewritten to "B".

Getting rid of what you no longer need with "config --unset" is the right thing to do, and you did fine in the previous example.

← back to recent threads