Does "git fetch --tags" include "git fetch"?

232,516

Solution 1

Note: starting with git 1.9/2.0 (Q1 2014), git fetch --tags fetches tags in addition to what are fetched by the same command line without the option.

To fetch only tags:

git fetch <remote> 'refs/tags/*:refs/tags/*'

In details:

See commit c5a84e9 by Michael Haggerty (mhagger):

Previously, fetch's "--tags" option was considered equivalent to specifying the refspec

refs/tags/*:refs/tags/*

on the command line; in particular, it caused the remote.<name>.refspec configuration to be ignored.

But it is not very useful to fetch tags without also fetching other references, whereas it is quite useful to be able to fetch tags in addition to other references.
So change the semantics of this option to do the latter.

If a user wants to fetch only tags, then it is still possible to specifying an explicit refspec:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Please note that the documentation prior to 1.8.0.3 was ambiguous about this aspect of "fetch --tags" behavior.
Commit f0cb2f1 (2012-12-14) fetch --tags made the documentation match the old behavior.
This commit changes the documentation to match the new behavior (see Documentation/fetch-options.txt).

Request that all tags be fetched from the remote in addition to whatever else is being fetched.


Since Git 2.5 (Q2 2015) git pull --tags is more robust:

See commit 19d122b by Paul Tan (pyokagan), 13 May 2015.
(Merged by Junio C Hamano -- gitster -- in commit cc77b99, 22 May 2015)

pull: remove --tags error in no merge candidates case

Since 441ed41 ("git pull --tags": error out with a better message., 2007-12-28, Git 1.5.4+), git pull --tags would print a different error message if git-fetch did not return any merge candidates:

It doesn't make sense to pull all tags; you probably meant:
      git fetch --tags

This is because at that time, git-fetch --tags would override any configured refspecs, and thus there would be no merge candidates. The error message was thus introduced to prevent confusion.

However, since c5a84e9 (fetch --tags: fetch tags in addition to other stuff, 2013-10-30, Git 1.9.0+), git fetch --tags would fetch tags in addition to any configured refspecs.
Hence, if any no merge candidates situation occurs, it is not because --tags was set. As such, this special error message is now irrelevant.

To prevent confusion, remove this error message.


With Git 2.11+ (Q4 2016) git fetch is quicker.

See commit 5827a03 (13 Oct 2016) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 9fcd144, 26 Oct 2016)

fetch: use "quick" has_sha1_file for tag following

When fetching from a remote that has many tags that are irrelevant to branches we are following, we used to waste way too many cycles when checking if the object pointed at by a tag (that we are not going to fetch!) exists in our repository too carefully.

This patch teaches fetch to use HAS_SHA1_QUICK to sacrifice accuracy for speed, in cases where we might be racy with a simultaneous repack.

Here are results from the included perf script, which sets up a situation similar to the one described above:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%

That applies only for a situation where:

  1. You have a lot of packs on the client side to make reprepare_packed_git() expensive (the most expensive part is finding duplicates in an unsorted list, which is currently quadratic).
  2. You need a large number of tag refs on the server side that are candidates for auto-following (i.e., that the client doesn't have). Each one triggers a re-read of the pack directory.
  3. Under normal circumstances, the client would auto-follow those tags and after one large fetch, (2) would no longer be true.
    But if those tags point to history which is disconnected from what the client otherwise fetches, then it will never auto-follow, and those candidates will impact it on every fetch.

Git 2.21 (Feb. 2019) seems to have introduced a regression when the config remote.origin.fetch is not the default one ('+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24 (Q4 2019) adds another optimization.

See commit b7e2d8b (15 Sep 2019) by Masaya Suzuki (draftcode).
(Merged by Junio C Hamano -- gitster -- in commit 1d8b0df, 07 Oct 2019)

fetch: use oidset to keep the want OIDs for faster lookup

During git fetch, the client checks if the advertised tags' OIDs are already in the fetch request's want OID set.
This check is done in a linear scan.
For a repository that has a lot of refs, repeating this scan takes 15+ minutes.

In order to speed this up, create a oid_set for other refs' OIDs.

Solution 2

Note: this answer is only valid for git v1.8 and older.

Most of this has been said in the other answers and comments, but here's a concise explanation:

  • git fetch fetches all branch heads (or all specified by the remote.fetch config option), all commits necessary for them, and all tags which are reachable from these branches. In most cases, all tags are reachable in this way.
  • git fetch --tags fetches all tags, all commits necessary for them. It will not update branch heads, even if they are reachable from the tags which were fetched.

Summary: If you really want to be totally up to date, using only fetch, you must do both.

It's also not "twice as slow" unless you mean in terms of typing on the command-line, in which case aliases solve your problem. There is essentially no overhead in making the two requests, since they are asking for different information.

Solution 3

I'm going to answer this myself.

I've determined that there is a difference. "git fetch --tags" might bring in all the tags, but it doesn't bring in any new commits!

Turns out one has to do this to be totally "up to date", i.e. replicated a "git pull" without the merge:

$ git fetch --tags
$ git fetch

This is a shame, because it's twice as slow. If only "git fetch" had an option to do what it normally does and bring in all the tags.

Solution 4

The general problem here is that git fetch will fetch +refs/heads/*:refs/remotes/$remote/*. If any of these commits have tags, those tags will also be fetched. However if there are tags not reachable by any branch on the remote, they will not be fetched.

The --tags option switches the refspec to +refs/tags/*:refs/tags/*. You could ask git fetch to grab both. I'm pretty sure to just do a git fetch && git fetch -t you'd use the following command:

git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

And if you wanted to make this the default for this repo, you can add a second refspec to the default fetch:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

This will add a second fetch = line in the .git/config for this remote.


I spent a while looking for the way to handle this for a project. This is what I came up with.

git fetch -fup origin "+refs/*:refs/*"

In my case I wanted these features

  • Grab all heads and tags from the remote so use refspec refs/*:refs/*
  • Overwrite local branches and tags with non-fast-forward + before the refspec
  • Overwrite currently checked out branch if needed -u
  • Delete branches and tags not present in remote -p
  • And force to be sure -f

Solution 5

In most situations, git fetch should do what you want, which is 'get anything new from the remote repository and put it in your local copy without merging to your local branches'. git fetch --tags does exactly that, except that it doesn't get anything except new tags.

In that sense, git fetch --tags is in no way a superset of git fetch. It is in fact exactly the opposite.

git pull, of course, is nothing but a wrapper for a git fetch <thisrefspec>; git merge. It's recommended that you get used to doing manual git fetching and git mergeing before you make the jump to git pull simply because it helps you understand what git pull is doing in the first place.

That being said, the relationship is exactly the same as with git fetch. git pull is the superset of git pull --tags.

Share:
232,516

Related videos on Youtube

davidA
Author by

davidA

Updated on October 06, 2021

Comments

  • davidA
    davidA over 2 years

    A nice and simple question - is the function of "git fetch" a strict sub-set of git fetch --tags?

    I.e. if I run git fetch --tags, is there ever a reason to immediately run git fetch straight afterward?

    What about git pull and git pull --tags? Same situation?

    • VonC
      VonC over 10 years
      Starting Git 1..9/2.0 (Q1 2014), the answer will be yes. See my answer below
    • davidA
      davidA almost 6 years
      To the editor who "corrected my text" with an edit - one does not necessarily capitalise after a hyphen or an acronym, so your edit was grammatically incorrect, which is why I rejected it.
  • VonC
    VonC over 14 years
    Interesting, I did not experienced that (probably because my repo was up to date at the time of my test.) +1
  • VonC
    VonC over 14 years
    How about a 'git remote update myRemoteRepo': would that fetch remote content and tags?
  • CB Bailey
    CB Bailey over 14 years
    git fetch --tags will bring in all commits needed to support tags on the remote repository, but it doesn't fetch commits on branches that aren't included in the set of tags on the remote repository.
  • Tim Visher
    Tim Visher over 14 years
    I do git fetch all the time and it consistently pulls down any new commits and any new tags. What version of Git are you running?
  • davidA
    davidA over 14 years
    That's not quite what I said - I said that "git fetch --tags" does not pull down new commits. It is not a super-set of "git fetch", which does pull down new commits. So if you want the behaviour of 'git fetch' and the behaviour of 'git fetch --tags', you have to run both of them. I'll look into 'git remote update myRemote'.
  • davidA
    davidA over 14 years
    Thanks for your comment. I'm running git in Cygwin over a high-latency network - it's twice as slow when there's nothing to fetch for either (about 5 seconds).
  • davidA
    davidA over 14 years
    "git pull is the superset of git pull --tags" - but... 'git fetch' is not the superset of 'git fetch --tags' so the relationship isn't exactly the same...?
  • davidA
    davidA over 14 years
    I think the issue is that 'git fetch' only fetches tags on tracked branches. We have a script that allows users to select a working branch, so by default there are many branches that are not currently tracked by an individual.
  • davidA
    davidA over 14 years
    I haven't tried git-remote yet, but it's on my ever-growing to-do list :)
  • Cascabel
    Cascabel over 14 years
    Edited to reflect the tracked branches only part. My mistake there - another default I don't mess with much.
  • davidA
    davidA over 14 years
    FTR, 'git remote update myRemoteRepo' does not work well - does not seem to do what 'git fetch && git fetch --tags' does, especially as a subsequent merge has no effect.
  • Arc
    Arc over 13 years
    Just found this question... well, it seems to me that git pull does not get all tags but only those reachable from the current branch heads. However, git pull --tags fetches all tags and is apparently equivalent to git fetch --tags.
  • larsks
    larsks over 11 years
    Note that git remote update is not actually a substitute for git fetch and git fetch --tags. git remote update will not update existing tags that have changed, although it will bring in new tags. Only git fetch --tags will update already existing tags.
  • gnarf
    gnarf about 11 years
    @TimVisher git fetch won't grab tags that aren't in the commit log of a branch. jQuery UI does this for instance on a release tag. We do a git checkout -b temp-branch, do our release, add files needed for the release, update version, etc, then git commit -m "1.10.x" ; git tag 1.10.x; git push --tags then we delete our local temp branch. There is no remote branch that reaches that tag, and git fetch will never download it.
  • gnarf
    gnarf about 11 years
    @Iarsks I removed the suggestion to remote update from the answer, I did some testing and proved your claim. Thanks for the comment it saved me thinking I'd found a solution.
  • gnarf
    gnarf about 11 years
    There is actually overhead in grabbing all that information twice, there is handshaking logging in, pack time, etc. You can do this with a single git fetch - see my answer.
  • Cascabel
    Cascabel about 11 years
    @gnarf Honestly, if tags are changing, the solution is to tell the repository owners to stop overwriting them. The point of tags is to mark fixed points in history.
  • Cascabel
    Cascabel about 11 years
    @gnarf Also, tags should in practice only be on branches, so fetching tags is just fetching refs, with no overhead in packing.
  • gnarf
    gnarf about 11 years
    @Jefromi we do not overwrite tags, but we orphan them. There are files added on every release that we do not want in the branches anywhere. A standard fetch does not retrieve them.
  • redolent
    redolent about 10 years
    This should be the answer.
  • Dmitry Minkovsky
    Dmitry Minkovsky about 10 years
    +1 for "The --tags option switches the refspec to +refs/tags/*:refs/tags/*". Although, man git-fetch, seems to specify that refspec without the leading + (refs/tags/*:refs/tags/*).
  • Rana Ghosh
    Rana Ghosh over 9 years
    "and all tags which are reachable from these branches" Can you elaborate on what this means? What can you do to make a tag reachable. What can you do to make it not reachable?
  • Cascabel
    Cascabel over 9 years
    @tieTYT "Reachable" means "in the history of", as in, reachable via the history graph, by going from a commit to its parent, to that commit's parent, and so on.
  • Robert Siemer
    Robert Siemer almost 9 years
    remote.origin.fetch defaults to +refs/heads/*:refs/remotes/origin/*, i.e. the + version, isn’t it? (That means, origin/branch will be overwritten, no matter where origin/branch is right now locally.)
  • Robert Siemer
    Robert Siemer almost 9 years
    ...and at the time of writing, recent git --tags were fetching tags in addition to everything else already. See @VonC ’s answer.
  • Christopher
    Christopher almost 9 years
    Another weird quirk with git remote update: it seems to re-download previously fetched tags, but it won't download any new ones. The only way to do that appears to be git fetch --tags.
  • ankostis
    ankostis over 6 years
    This thread in git-list discusses the possibility to amend the behavior of git fetch <remote> <branch> to auto-follow tags (since it already updates remote-trackings AGAINST original intentions): public-inbox.org/git/…
  • VonC
    VonC over 6 years
    @ankostis Interesting: as Junio mentions in public-inbox.org/git/…, "going back to the old behaviour may be one option to address the issue being discussed in this thread." (but they won't: public-inbox.org/git/…)
  • John Fantastico
    John Fantastico about 5 years
    Would it have been possible for Git to expose more unnecessary complexity to the end-user, requiring syntax-heavy commands to the point of resembling hacks to perform common operations? I don't think enough of the internals are required knowledge yet.
  • VonC
    VonC about 5 years
    @JohnFantastico I can understand that point of view. I have seen that before: news.ycombinator.com/item?id=16587496. Or hackernoon.com/… ("The Git commands are just a leaky abstraction over the data storage.")
  • Vadorequest
    Vadorequest about 5 years
    @VonC Using git v2.21, a new behaviour has broken the old behaviour. I don't know the details but basically it breaks git clone if fetch = +refs/tags/*:refs/tags/* is used (in .gitconfig, for instance). Maybe you want to update your answer? I would but I don't know what has changed under the hood so I can't really explain it properly. See apple.stackexchange.com/questions/352404/…
  • VonC
    VonC about 5 years
    @Vadorequest Thank you. I have updated the answer and will keep a look out to the mailing list: public-inbox.org/git/?q=fetch
  • Gabriel Staples
    Gabriel Staples about 3 years
    I'd like to emphasize this part of the answer: git fetch <remote> 'refs/tags/*:refs/tags/*' to fetch ONLY tags! Super useful. Just what I needed.
  • VonC
    VonC about 3 years
    @GabrielStaples Good point. I have edited the answer accordingly.