Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> writes: > > Tags need not be pointing at commits so there is no way to > > guarantee "fast-forward" anyway. The observation the above statement makes is not incorrect per-se, but it does not justify "anything goes". "nothing is allowed unless forced" is equally a logical consequence of the observation. > That comment and the rest of the history of "fetch" shows that the > "+" (--force) part of refpecs was only conceived for branch updates, > while tags have accepted any changes from upstream unconditionally and > clobbered the local tag object. Changing this behavior has been > discussed as early as 2011[1]. Thanks for a pointer. We didn't keep reflog on tags as we wanted tags to be fixed points and made --tags a refspec without leading '+' because we didn't want this local clobbering. I'd say it is just a buggy implementation, and we should just implement a simple rule "refs/tags/* is never updated unless forced". > I the current behavior doesn't make sense, it easily results in local s/I the/To me, the/, or s/I the/The/. > tags accidentally being clobbered. Ideally we'd namespace our tags > per-remote, but as with my 97716d217c ("fetch: add a --prune-tags > option and fetch.pruneTags config", 2018-02-09) it's easier to work > around the current implementation than to fix the root cause, I do not think they are the same problem. You can have refs/remote/$name/v1.0 and have look-up rules to peek at various places in refs/* hierarchy for v1.0, and you may have *solved* the "oops I overwrote and the meaning of v1.0 suddenly changed" issue, but if you fetched to a location in refs/* that has higher precedence, then "oops, the meaning of v1.0 suddenly changed" issue itself is *not* solved at all. > so this > implements suggestion #1 from [1], "fetch" now only clobbers the tag > if either "+" is provided as part of the refspec, or if "--force" is > provided on the command-line. Good. Regardless of the issue of separate namespace that is overlayed at the look-up time, this makes tons of sense. > diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt > index 8631e365f4..5b4fc36866 100644 > --- a/Documentation/fetch-options.txt > +++ b/Documentation/fetch-options.txt > @@ -49,11 +49,16 @@ endif::git-pull[] > > -f:: > --force:: > - When 'git fetch' is used with `<rbranch>:<lbranch>` > - refspec, it refuses to update the local branch > - `<lbranch>` unless the remote branch `<rbranch>` it > - fetches is a descendant of `<lbranch>`. This option > - overrides that check. > + When 'git fetch' is used with `<src>:<dst>` refspec it might Nice to see attention to the detail here. s/might/may/, I would say, though. > + refuse to update the local branch as discussed > diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt > index c579793af5..672e8bc1c0 100644 > --- a/Documentation/pull-fetch-param.txt > +++ b/Documentation/pull-fetch-param.txt > @@ -32,12 +32,22 @@ name. > `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`; > it requests fetching everything up to the given tag. > + > -The remote ref that matches <src> > -is fetched, and if <dst> is not empty string, the local > -ref that matches it is fast-forwarded using <src>. > -If the optional plus `+` is used, the local ref > -is updated even if it does not result in a fast-forward > -update. > +The remote ref that matches <src> is fetched, and if <dst> is not > +empty string, an attempt is made to update the local ref that matches > +it. > ++ > +Whether that update is allowed is confusingly not the inverse of > +whether a server will accept a push as described in the `<refspec>...` > +section of linkgit:git-push[1]. If it's a commit under `refs/heads/*` > +only fast-forwards are allowed, Perhaps correct. It is unclear what happens when it is fetching non-commit to refs/heads/* in the above sentence. > but unlike what linkgit:git-push[1] > +will accept clobbering any ref pointing to blobs, trees etc. in any > +other namespace will be accepted, but commits in any ref > +namespace. ... I cannot quite parse this. > +... Those apply the same fast-forward rule. Who are "Those"? refs/poo/*? > +... An exception to > +this is that as of Git version 2.18 any object under `refs/tags/*` is > +protected from updates. OK. > +If the optional plus `+` is used, the local ref is updated if the Tighten "is used" to claify that you are talking about the '+' prefix that signals a forced push/fetch. We do not want to hear from people who complain their "git fetch origin master+" does not work. > - OPT__FORCE(&force, N_("force overwrite of local branch"), 0), > + OPT__FORCE(&force, N_("force overwrite of local reference"), 0), Good. This is long overdue.