11

I have created a sandbox git repository containing a few commits and a couple of tags, one lightweight and one annotated:

> mkdir one; cd one; git init

> touch a.txt; git add a.txt; git commit -m"a.txt"

> touch b.txt; git add b.txt; git commit -m"b.txt"
> git tag light

> touch c.txt; git add c.txt; git commit -m"c.txt"
> git tag -a annot -m"annot"

I now create a second repository and fetch from the first:

> mkdir two; cd two; git init

> git remote add one <...>/one
> git fetch one master
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From <...>/one
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> one/master

Why have neither of the tags been fetched? I expected they would be, based on the documentation for git fetch:

By default, any tag that points into the histories being fetched is also fetched; the effect is to fetch tags that point at branches that you are interested in.

user200783
  • 13,722
  • 12
  • 69
  • 135
  • did you try `git fetch --all` – Chandan Rai Jan 23 '17 at 19:01
  • I'm nearly certain Git's tag handling has changed significantly over the years, so: which Git *version* are you running? (And, if this is on two separate machines, what URL scheme, http:// vs git:// vs ssh://, are you using and give both machines' Git versions...) – torek Jan 23 '17 at 19:22
  • @crai - Both `git fetch --tags one master` and plain `git fetch one` fetch the `one/master` branch and both `light` and `annot` tags. However, `git fetch one master` does not fetch the tags - I am trying to understand why. – user200783 Jan 23 '17 at 19:23
  • @torek - I am using the latest git version, 2.11.0. Both repositories are on the same machine, using the `file://` URL scheme. – user200783 Jan 23 '17 at 19:25

2 Answers2

16

Not a true answer but I got here via Google search because git fetch was not pulling my tags (and usually does). So this is for anyone else in the same boat who stumbles upon this very similarly worded question.

I was able to manually pull the tag with: git fetch --tags

rotarydial
  • 2,181
  • 2
  • 23
  • 27
danielson317
  • 3,121
  • 3
  • 28
  • 43
8

Edit, Jan 2020, per Tim Bunce's comment: the behavior was deemed to be a bug and changed in Git 2.20 to be more sensible. The tests below are for significantly older versions of Git.


Updated with new interesting informational bits. I put this into a shell script for easy testing:

mkdir ttwo && cd ttwo && git init && git remote add one file://[path]

(and then I remove ttwo after running a test).

Hence each test below is run in the new empty ttwo. I am also using Git 2.10.1 here, but there should be no significant differences with 2.11 (while there are definitely significant differences compared with Git 1.7, which is still shipping with certain Linux distributions...).

First, let's git fetch with no refspecs:

$ git fetch one
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From file://[path]
 * [new branch]      master     -> one/master
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light

This is with Git version 2.10.1, with both repositories on the same machine, and using either file:///home/... or /home/.... Both fetches (rm -rf texp2 in between as needed) picked up both tags.

Now let's run it with the single refspec master. From here on I'll leave out the remote: through From: stuff, just show what branches and/or tags get updated:

$ git fetch one master
[snip]
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> one/master

Here's what happens if we use master:master, which requires adding --update-head-ok:

$ git fetch one --update-head-ok master:master
 * [new branch]      master     -> master
 * [new tag]         annot      -> annot
 * [new branch]      master     -> one/master
 * [new tag]         light      -> light

Aha, now we get tags!

Here's what happens if we fetch master but write it to refs/remotes/origin/master:

$ git fetch one master:refs/remotes/origin/master
 * [new branch]      master     -> origin/master
 * [new tag]         annot      -> annot
 * [new branch]      master     -> one/master
 * [new tag]         light      -> light

There is a pattern emerging: we have to write to some local ref(s)

Let's fetch master to x and light to dark (I tried foo to bar but that doesn't work because foo does not exist in repo one):

$ git fetch one master:x light:dark
 * [new branch]      master     -> x
 * [new tag]         light      -> dark
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light
 * [new branch]      master     -> one/master

Now let's fetch master to nothing, which we know fails standalone, but fetch light to dark:

$ git fetch one master light:dark
 * branch            master     -> FETCH_HEAD
 * [new tag]         light      -> dark
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light
 * [new branch]      master     -> one/master

And one last test:

$ git fetch one master light
 * branch            master     -> FETCH_HEAD
 * tag               light      -> FETCH_HEAD
 * [new branch]      master     -> one/master

This did not write to our tags, only to FETCH_HEAD, plus the usual opportunistic remote-tracking branch update.

The bottom line appears to be that, when giving explicit refspecs, we must write at least one local ref. Fetching with no refspecs works, because that uses the default refspecs in the config file plus the default tags. Fetching with some refspec(s) that write to a local ref works. Fetching with some refspec(s) that only write to FETCH_HEAD fails. This seems like a bug, but it's not clear what the intent of the code in Git is, and Git's tag update code is horribly twisty.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Using `git fetch one` like this fetches the `one/master` branch and both `light` and `annot` tags for me too. However, I was expecting `git fetch one master` to also fetch the tags - I am trying to understand why it does not. – user200783 Jan 23 '17 at 22:09
  • Oh, I see, you gave an *explicit refspec*. The tags code inside Git is very twisty, so I don't know *why* that fails, but obviously it does. – torek Jan 23 '17 at 22:18
  • Are you able to reproduce the problem using `git fetch one master`? – user200783 Jan 23 '17 at 22:29
  • Yes. Works with no refspec, fails with a refspec with no local name. Will update answer with more. – torek Jan 23 '17 at 22:40
  • 1
    Thank you so much for doing all these tests! Based on the evidence, it does indeed seem that to get the tags, at least one explicit refspec must have an explicit destination. It therefore looks like the way to fetch `master` along with the relevant tags would be `git fetch one master:refs/remotes/one/master`. Is this the command you would recommend using in place of `git fetch one master`? – user200783 Jan 25 '17 at 01:48
  • 1
    @user200783: yes, assuming the standard (non-mirror-style, no other funny business with the `fetch` refspec in the config) configuration. If you wanted to be extra paranoid in a script, you could run `git config --get-all remote.one.fetch` and parse the resulting output. I probably would just `git fetch one master:refs/remotes/one/master`. :-) – torek Jan 25 '17 at 01:56
  • Thanks for the confirmation. There is no unusual configuration involved, so I will just use `git fetch one master:refs/remotes/one/master`. Do you think the fact that this behaves differently to `git fetch one master` should be reported as a bug in Git? – user200783 Jan 25 '17 at 02:04
  • 1
    Seems like it's either a behavior bug or a documentation bug, yes. There's no mention that default-tags is defeated by a remote-only refspec... – torek Jan 25 '17 at 02:15
  • Great thanks @torek; I would have never guessed why related tags are not fetched. What the manual says on the matter is bs. – ankostis Aug 08 '17 at 02:38
  • 2
    FYI The behaviour changed in git 2.20 per https://git-scm.com/docs/git-fetch "Since Git version 2.20, fetching to update refs/tags/* works the same way as when pushing. I.e. any updates will be rejected without + in the refspec (or --force)." – Tim Bunce Jan 27 '20 at 17:27