threads / discuss / 60584

git switch has fatal dependency on default fetch config

Subject: git switch has fatal dependency on default fetch config

## tl;dr

3 messages between Dec 6, 2023 and Dec 7, 2023.

replies: 2people: 2as markdown or json

Jeremiah Steele (Jerry)· Dec 6, 2023, 03:41 UTC · lore
Changing the default fetch refspec for a remote breaks git switch:
% git branch -r
  origin/HEAD -> origin/master
  origin/feature
  origin/master
% git remote set-branches origin master
% git switch -c feature --track origin/feature
fatal: cannot set up tracking information; starting point 'origin/feature' is not a branch
% git remote set-branches --add origin feature
% git switch -c feature --track origin/feature
branch 'feature' set up to track 'origin/feature'.
Switched to a new branch 'feature'
It seems like I should be able to fetch a remote branch and track it without having to monkey around with my default fetch config. Is there a reason git switch has a hard dependency on the default remote fetch refspec configuration?
Jeff King· Dec 6, 2023, 19:11 UTC · re: Jeremiah Steele (Jerry) · lore

Re: git switch has fatal dependency on default fetch config

On Tue, Dec 05, 2023 at 07:41:28PM -0800, Jeremiah Steele (Jerry) wrote:
Show 18 quoted lines
> Changing the default fetch refspec for a remote breaks git switch:
> 
> % git branch -r
>   origin/HEAD -> origin/master
>   origin/feature
>   origin/master
> % git remote set-branches origin master
> % git switch -c feature --track origin/feature
> fatal: cannot set up tracking information; starting point 'origin/feature' is not a branch
> % git remote set-branches --add origin feature
> % git switch -c feature --track origin/feature
> branch 'feature' set up to track 'origin/feature'.
> Switched to a new branch 'feature'
> 
> It seems like I should be able to fetch a remote branch and track it
> without having to monkey around with my default fetch config. Is there
> a reason git switch has a hard dependency on the default remote fetch
> refspec configuration?

I think it's required by the form of the tracking config, which is defined by a named remote and a remote branch, like:

  [branch "foo"]
  remote = origin
  merge = refs/heads/foo

You explicitly asked to track "origin/feature", which means that Git has to be able to turn that into config as above. It can handle two cases:

  1. It's a local branch in refs/heads/, in which case the remote is "."
     and the "merge" field is the name of the branch.
  2. It's a ref that can be found by reversing a fetch refspec. With the
     default remote.origin.fetch refspec of refs/heads/*:refs/remotes/origin/*,
     we know that "refs/remotes/origin/feature" comes from "refs/heads/feature"
     on the "origin" remote.
     But since you used "remote set-branches" to limit that refspec, we
     can't do that same reversal. And "origin/feature", while we do
     still have it as a ref, does not correspond to any remote ref we'd
     fetch. So we don't know how to set up the tracking config.

The notion of "tracking" really came about as defining what "git pull" does. And without a remote that fetches, "git pull" does not really make much sense.

I'd guess that you are more interested in being able to just use @{upstream}, especially as the default for things like rebase, etc. And that could work without being able to actually fetch the ref. But those two things are intertwined in Git. You obviously can still base a branch off of "origin/feature", but you'll have to specify it manually when doing rebase, etc.

-Peff
Jeremiah Steele (Jerry)· Dec 7, 2023, 02:20 UTC · re: Jeff King · lore

Re: git switch has fatal dependency on default fetch config

For me, the main convenience of upstream tracking is for "git status" ahead/behind info, which requires you to have already fetched changes from the remote. For my "normal" work, I have a small set of branches set as default fetch refs. When I need to work on a branch not in that set, I fetch that specific branch. (I'm not interested in downloading and creating hundreds of branches when I only need one.)
The requirement to reverse-engineer from the *default* fetch refspec seems like an odd implementation choice and a major shortcoming for storing tracking configuration. The vast majority of the time, origin/branch will map to refs/heads/branch on the remote anyhow. When I have a command that sets up tracking configuration, I would expect to be able to specify the remote refspec somehow, rather than having a hard dependency on a configuration value for default behavior. I feel like the following sequence should work as expected (with a limited default fetch spec), but there are several things that go wrong:

% git fetch origin feature # should fetch to refs/remotes/origin/feature % git switch feature # should find origin/feature, create a local branch with the same name, and set up tracking

Oh well.
Thanks for the response and the explanation.
Show 58 quoted lines
> On Dec 6, 2023, at 11:11 AM, Jeff King <peff@peff.net> wrote:
> 
> On Tue, Dec 05, 2023 at 07:41:28PM -0800, Jeremiah Steele (Jerry) wrote:
> 
>> Changing the default fetch refspec for a remote breaks git switch:
>> 
>> % git branch -r
>>  origin/HEAD -> origin/master
>>  origin/feature
>>  origin/master
>> % git remote set-branches origin master
>> % git switch -c feature --track origin/feature
>> fatal: cannot set up tracking information; starting point 'origin/feature' is not a branch
>> % git remote set-branches --add origin feature
>> % git switch -c feature --track origin/feature
>> branch 'feature' set up to track 'origin/feature'.
>> Switched to a new branch 'feature'
>> 
>> It seems like I should be able to fetch a remote branch and track it
>> without having to monkey around with my default fetch config. Is there
>> a reason git switch has a hard dependency on the default remote fetch
>> refspec configuration?
> 
> I think it's required by the form of the tracking config, which is
> defined by a named remote and a remote branch, like:
> 
>  [branch "foo"]
>  remote = origin
>  merge = refs/heads/foo
> 
> You explicitly asked to track "origin/feature", which means that Git has
> to be able to turn that into config as above. It can handle two cases:
> 
>  1. It's a local branch in refs/heads/, in which case the remote is "."
>     and the "merge" field is the name of the branch.
> 
>  2. It's a ref that can be found by reversing a fetch refspec. With the
>     default remote.origin.fetch refspec of refs/heads/*:refs/remotes/origin/*,
>     we know that "refs/remotes/origin/feature" comes from "refs/heads/feature"
>     on the "origin" remote.
> 
>     But since you used "remote set-branches" to limit that refspec, we
>     can't do that same reversal. And "origin/feature", while we do
>     still have it as a ref, does not correspond to any remote ref we'd
>     fetch. So we don't know how to set up the tracking config.
> 
> The notion of "tracking" really came about as defining what "git pull"
> does. And without a remote that fetches, "git pull" does not really make
> much sense.
> 
> I'd guess that you are more interested in being able to just use
> @{upstream}, especially as the default for things like rebase, etc. And
> that could work without being able to actually fetch the ref. But those
> two things are intertwined in Git. You obviously can still base a branch
> off of "origin/feature", but you'll have to specify it manually when
> doing rebase, etc.
> 
> -Peff

← back to recent threads