Skip to content
  • Ævar Arnfjörð Bjarmason's avatar
    fetch: stop clobbering existing tags without --force · 0bc8d71b
    Ævar Arnfjörð Bjarmason authored and Junio C Hamano's avatar Junio C Hamano committed
    Change "fetch" to treat "+" in refspecs (aka --force) to mean we
    should clobber a local tag of the same name.
    
    This changes the long-standing behavior of "fetch" added in
    853a3697 ("[PATCH] Multi-head fetch.", 2005-08-20). Before this
    change, all tag fetches effectively had --force enabled. See the
    git-fetch-script code in fast_forward_local() with the comment:
    
        > Tags need not be pointing at commits so there is no way to
        > guarantee "fast-forward" anyway.
    
    That commit 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].
    
    The current behavior doesn't make sense to me, it easily results in
    local tags accidentally being clobbered. We could namespace our tags
    per-remote and not locally populate refs/tags/*, but as with my
    97716d21 ("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.
    
    So this change implements suggestion #1 from Jeff's 2011 E-Mail[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.
    
    This also makes it nicely symmetrical with how "tag" itself works when
    creating tags. I.e. we refuse to clobber any existing tags unless
    "--force" is supplied. Now we can refuse all such clobbering, whether
    it would happen by clobbering a local tag with "tag", or by fetching
    it from the remote with "fetch".
    
    Ref updates outside refs/{tags,heads/* are still still not symmetrical
    with how "git push" works, as discussed in the recently changed
    pull-fetch-param.txt documentation. This change brings the two
    divergent behaviors more into line with one another. I don't think
    there's any reason "fetch" couldn't fully converge with the behavior
    used by "push", but that's a topic for another change.
    
    One of the tests added in 31b808a0 ("clone --single: limit the fetch
    refspec to fetched branch", 2012-09-20) is being changed to use
    --force where a clone would clobber a tag. This changes nothing about
    the existing behavior of the test.
    
    1. https://public-inbox.org/git/20111123221658.GA22313@sigill.intra.peff.net/
    
    
    
    Signed-off-by: default avatarÆvar Arnfjörð Bjarmason <avarab@gmail.com>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    0bc8d71b