Subject: Re: [PATCH v13 8/9] fetch: set remote/HEAD if it does not exist

From: Junio C Hamano <[email-masked]>
Date: Wed, 20 Nov 2024 10:00:37 +0900

"Bence Ferdinandy" <[email-masked]> writes:

> Your suggestion seems to be the original tri-state configuration that came up
> in one of the original discussions. It was recently requested again for fetch
> to just do this automatically
> (https://lore.kernel.org/git/CAAHKNRGv19rhnqCkJMpE2FomNQBHvSS36aC=[email-masked]),
> so at least some people would like to have this fully automated.

And that is *not* the only option, and I am trying to help others
by preventing unconditional warning messages from annoying them.

> On the other hand: considering your points in the linked very early discussion,
> maybe "warn" would be a better default?

Those who want to stick to their manual choice would have to do an
explicit set-head once, whether the default is "true" or "warn", so
their inconvenience would not affect the choice of the default.

I think "warn" is a good default _only_ for folks who want to verify
and then expect they will follow what the upstream does 99% of the
time.  For them, when they do not want to switch to what the
upstream says (which is the rest 1%), there is no good way to
squelch the warning other than dropping the configuration, but then
they will lose the ability to notice further flips at the remote
after that, which may turn out to be a problem.

Instead of "true", "warn", and "false", we might need "if it is set
to _this_ value, do not warn and keep the current setting" to help
those who cautiously only allow the remote affect what they use
after inspecting, but expect that the choice made by the remote will
not be outrageous most of the time for them.

If we want to solve this completely for them, that is.  I dunno.

Those who want to blindly follow what the upstream says 100% of the
time will have to switch to "true" just once manually, if the
default were "warn", but once may be one time too many for them.

And that is why I said "clone" (and "fetch" setting a non-existing
HEAD automatically) may want to default to "true".

> Fair point.
>
> This series has a tendency for growing in complication in each iteration :)

Anytime somebody gets swayed by an opinion to add unconditional
warning or unconditional futzing without considering that such a
move may annoy some users that are different from the opinion giver,
we need to make sure there are escape hatches.  Under the assumption
that most projects only flip HEAD very rarely, and considering the
fact that we have lived with manual setting with set-head and
nothing else, we could drop the automatic setting by "fetch"
altogether to reduce the scope of the series without losing much
*and* more importantly without harming existing users.

I think we could make it a multi-step transition in order to keep
changes to "git fetch" we make in each step smaller, which may go
like so:

 1) Let "git fetch" create missing remotes/$name/HEAD.  No other
    changes.

 2) Introduce a remote.$name.followRemoteHEAD that can say "the last
    branch we observed that they point at is 'main'".  Set it when
    we clone, When "git fetch" notices that the remote flipped its
    HEAD to a different value, warn and update (which would give us
    the "warn only once, do not annoy users by constantly warning").
    The user can delete the configuration to squelch "git fetch" (in
    other words, the repository does not remember the last setting,
    so we refrain from warning "it has changed since the last time").
    No other changes.

 3) Allow remote.$name.followRemoteHEAD to be set to

    3-a) "always", which would squelch the warning and causes "git
    fetch" to always repoint the local remotes/$name/HEAD to
    whatever the remote says,

    3-b) "warn", which would cause "git fetch" to warn when the
    remote's HEAD is different from local remotes/$name/HEAD,

    3-c) "never", which would cause "git fetch" to even omit the
    "copy if it does not exist" we add in 1) to help those who
    deliberately want to keep remotes/$name/HEAD missing (to force
    themselves to be more explicit, saying things like "git checkout
    -b topic origin/maint" and "git rebase origin/master", but never
    "git checkout --detach origin").

And we can stop this round at the first step (plus any other changes
outside "git fetch", like "set-head --auto").

Thanks.