This is my proposed fix for the local tag killer problem that I
reported recently [1].
There are three main things changed by this patch series:
1. git fetch --tags causes tags to be fetched *in addition to* any
other refspecs that are configured for the remote, rather than
*instead of*. I believe this is more useful behavior. It is also
consistent with the documentation as it was written before it was
disambiguated in 1.8.0.3.
2. git fetch --prune only prunes references that match an explicit
refspec (either from the command line or from the
remote.name.fetch configuration. In particular, using --prune
and --tag together do *not* make tags subject to pruning. (Tags
can still be pruned if the user specifies an explicit refspec
refs/tags/*:refs/tags/*.)
3. Previously, if the user invoked one of the following commands with
--no-prune, the --no-prune option was not passed to the git fetch
subprocesses that they invoked to do their work:
git fetch --all
git fetch --multiple
git fetch --recurse-submodules
git remote update
If fetch.prune or remote.name.prune were set to true, this could
result in unwanted reference pruning. The last commit in the
series fixes this bug and should not be controversial.
I had originally planned to solve the local tag killer problem by
adding a new configuration option to define which reference namespaces
were subject to pruning (e.g.,
remote.name.pruneRef=refs/remotes/*). I may yet submit that patch
series as a separate feature. But while working on it I hit on the
present solution, which I think is simpler and more elegant (albeit a
bit less flexible).
Changes (1) and (2) introduce behavior changes, but I think that they
are improvements and that the resulting backwards-incompatibility is
acceptable:
Change (1) means that git fetch --tags remote without any
additional refspec arguments will fetch more references than it did
before. But I don't think it is very useful to want to fetch tags
without fetching other configured references, so I think it is OK [2].
Change (2) means that using git fetch --tags --prune will *not*
prune tags. (This is the whole point of the change!) As discussed in
the mailing list, it is usually bad policy to prune tags, because tags
for the local repository and for all remote repositories currently
share a single namespace, refs/tags/*. Therefore, pruning tags
based on information from a single remote risks pruning local tags or
tags that have been obtained from another remote. The main exception,
when one probably *does* want to prune tags, is when fetching into a
mirror clone. But mirror clones have
remote.name.fetch=+refs/*:refs/*, and so even after this change
tags will be subject to pruning when fetching into a mirror clone.
The only other place I can find that does reference pruning is git
remote prune, but that codepath didn't respect remote.name.tagopt
anyway and therefore it *didn't* prune tags unless they were part of
an explicit refspec; i.e., this codepath already behaved the new way
that other pruning codepaths now behave.
Patches 1-9 are just preliminary cleanup and documentation
improvements.
Patch 10 implements change (1) described above.
Patch 11 implements change (2).
Patches 12-14 are some more minor cleanups.
Patch 15 implements change (3).
[1] http://article.gmane.org/gmane.comp.version-control.git/234723
[2] Indeed, I bet that most scripts that invoke git fetch --tags
remote also invoke a plain git fetch immediately before or
after to get the rest of the references.
Michael Haggerty (15):
t5510: use the correct tag name in test
t5510: prepare test refs more straightforwardly
t5510: check that git fetch --prune --tags does not prune branches
api-remote.txt: correct section struct refspect
get_ref_map(): rename local variables
ref_remove_duplicates(): avoid redundant bisection
ref_remove_duplicates(): simplify function
ref_remove_duplicates(): improve documentation comment
builtin/fetch.c: reorder function definitions
fetch --tags: fetch tags *in addition to* other stuff
fetch --prune: prune only based on explicit refspecs
query_refspecs(): move some constants out of the loop
builtin/remote.c: reorder function definitions
builtin/remote.c:update(): use struct argv_array
fetch, remote: properly convey --no-prune options to subprocesses
Documentation/config.txt | 2 +-
Documentation/fetch-options.txt | 21 ++-
Documentation/technical/api-remote.txt | 20 +--
builtin/fetch.c | 253 +++
builtin/remote.c | 196
git-pull.sh | 2 +-
remote.c | 44 +++---
remote.h | 9 +-
t/t5510-fetch.sh | 36 -
t/t5515/fetch.br-unconfig_--tags_.._.git | 1 +