On Mon, Jan 22 2018, Junio C. Hamano jotted: > Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> writes: > >> Add a --fetch-prune option to git-fetch, along with fetch.pruneTags >> config option. This allows for doing any of: >> >> git fetch -p -P >> git fetch --prune --prune-tags >> git fetch -p -P origin >> git fetch --prune --prune-tags origin >> >> Or simply: >> >> git config fetch.prune true && >> git config fetch.pruneTags true && >> git fetch >> >> Instead of the much more verbose: >> >> git fetch --prune origin 'refs/tags/*:refs/tags/*' '+refs/heads/*:refs/remotes/origin/*' >> >> Before this feature it was painful to support the use-case of pulling >> from a repo which is having both its branches *and* tags deleted >> regularly, and wanting our local references to reflect upstream. >> >> At work we create deployment tags in the repo for each rollout, and >> there's *lots* of those, so they're archived within weeks for >> performance reasons. >> >> Without this change it's hard to centrally configure such repos in >> /etc/gitconfig (on servers that are only used for working with >> them). You need to set fetch.prune=true globally, and then for each >> repo: >> >> git -C {} config --replace-all remote.origin.fetch "refs/tags/*:refs/tags/*" "^refs/tags/*:refs/tags/*$" > > I think the last one is supposed to be a regular expression on > existing values. Shouldn't the asterisks be quoted? > > Otherwise, it would appears as if "refs/tags:refs/tags///" are > replaced with "refs/tags/*:refs/tags/*", but it certainly is not > what you are doing. Yes, well spotted. I copied this from an escaped version and forgot to update that escaping. Will fix. > I also wonder why the existing one does not expect a leading '+', > which I think is what we place by default when you clone. I didn't raise this because I didn't want to get side-tracked with yet another thing, but it appears to me that a + prefix in tags refspecs does absolutely nothing. Consider on a fresh git.git clobbering the new v2.16.1 tag locally: $ git tag -a -m"fake" -f v2.16.1 v2.16.0 Updated tag 'v2.16.1' (was eb5fcb24f) This should clobber it, and does: $ git fetch --prune --dry-run origin '+refs/tags/*:refs/tags/*' From github.com:git/git t [tag update] v2.16.1 -> v2.16.1 But so will this without +, which seems like a bug to me: $ git fetch --prune --dry-run origin 'refs/tags/*:refs/tags/*' From github.com:git/git t [tag update] v2.16.1 -> v2.16.1 But maybe I'm missing something. >> +-P:: >> +--prune-tags:: >> + .... This option is >> + merely a shorthand for providing the explicit tag refspec >> + along with `--prune`, see the discussion about that in its >> + documentation. > > So would "git fetch -P origin" be like "git fetch --prune --tags > origin"? No, as I understand it --tags just has the effect of considering remote tags that aren't tags of the branches you're fetching, so e.g. on a fresh git.git: $ git tag -a -m"fake" -f v2.16.2 v2.16.0 $ git fetch --prune --tags --dry-run $ I.e. it does nothing. Whereas this will prune the new fake tag: $ git fetch --prune origin 'refs/tags/*:refs/tags/*' From github.com:git/git - [deleted] (none) -> v2.16.2 And so does the --prune-tags option: $ ~/g/git/git-fetch --prune --prune-tags origin From github.com:git/git - [deleted] (none) -> v2.16.2 >> + >> See the PRUNING section below for more details. >> >> diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt >> index 18fac0da2e..5682ed4ae1 100644 >> --- a/Documentation/git-fetch.txt >> +++ b/Documentation/git-fetch.txt >> @@ -148,6 +148,30 @@ So be careful when using this with a refspec like >> `refs/tags/*:refs/tags/*`, or any other refspec which might map >> references from multiple remotes to the same local namespace. >> >> +Since keeping up-to-date with both branches and tags on the remote is >> +a common use-case the `--prune-tags` option can be supplied along with >> +`--prune` to prune local tags that don't exist on the remote. Tag >> +pruning can also be enabled with `fetch.pruneTags` or >> +`remote.<name>.pruneTags` in the config. See linkgit:git-config[1]. >> + >> +The `--prune-tags` option is equivalent to having >> +`refs/tags/*:refs/tags/*` configured in the refspecs for the >> +remote. This can lead to some seemingly strange interactions: >> + >> +------------------------------------------------ >> +# These both fetch tags >> +$ git fetch --no-tags origin 'refs/tags/*:refs/tags/*' >> +$ git fetch --no-tags --prune-tags origin >> +------------------------------------------------ > > This description is too confusing. First you say "having > ... configured in the refspecs for the remote", but configured > refspecs for the remote (I presume that you are missing 'fetch' from > that description and are talking about the "remote.$name.fetch" > configuration variable) are overridden when you give explicit > refspecs from the command line, so the above two are not even > equivalent. The first one gives a refspec explicitly from the > command line, so other configured refspecs like > > [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* > > should be ignored, while the second one, if --prune-tags tells Git > to behave as if > > [remote "origin"] fetch = refs/tags/*:refs/tags/* > > also exists in the config, would not cause other ones for the same > remote from getting ignored. So... Indeed, I'll reword this. FWIW I meant something closer to "declared in the refspecs of the remote" not "configured ... remote".