tags:

views:

2162

answers:

2

Hi,

I am having a hard time understanding the nuances of git-fetch. I understand that doing a fetch, fetches the remote refs into a local tracking branch.

I have a few questions though:

  1. Can it be possible that a local tracking branch does not exist? If so, then will it be created automatically?

  2. What will happen if I do a fetch and specify a non tracking branch as the destination?

  3. The man page for git-fetch specifies git-fetch How would I use the refspec to fetch contents form my remote master into it's remote tracking branch? I believe this may be possible if I current HEAD is on master and I run

git fetch origin master

However, can I use the <+?src:dest> refpec to achieve the same thing? I think this will help me understand the concepts better.

And one more question:

My .git/config file has the following line for fetching (showing only relevant lines):

fetch = +refs/heads/*:refs/remotes/origin/*

Can someone please explain what this line exactly means.

Thanks in advance for the help.

--
Regards
Parag

+11  A: 

First, there's no such concept of local tracking branches, only remote tracking branches. So origin/master is a remote tracking branch for master in the origin repo.

Typically you do git fetch $remote which updates all your remote tracking branches, and creates new ones if needed.

However, you can also specify a refspec, but that will not touch your remote tracking branches, instead, it will fetch the branch you specified and save it on FETCH_HEAD, unless you specify a destination. In general you don't want to mess with this.

Finally,

fetch = +refs/heads/*:refs/remotes/origin/*

That means if you do

git fetch origin

It will actually do:

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

Which means a remote heads/foobar will be local remotes/origin/foobar, and the plus sign means they'll be updated even if they are not fast-forward.

Perhaps what you think as a tracking branch is something related to git pull and the merge config.

felipec
I was about to start answering this question when you added this response. I couldn't have said it better. +1
Dan Moulding
Hi felipic, Thanks for your answer. It helped clear many of my doubts. One question about the remote tracking branch.If I understand correctly, the remote tracking branch exists in my current repository and is meant to track the code which exists in some other (the remote) repository. If this is true, then would it be proper to say that the remote tracking branch is like a proxy of the actual branch which exists in the remote repository?
Parag
Yes, exactly, it's meant to be like a cached view of the remote repo that you can update at will.
felipec
Thanks Felipic, Thanks. One more question. If I want to refer to the actual remote repo (for the purpose of diffing my remote tracking branch with the actual remote branch), then can I do it with origin/master, or should I use the URL of the remote repo to refer to it? git diff origin/master refs/remotes/origin/master--Thanks Parag
Parag
+8  A: 

felipec have answered most of issues in question in his answer.

A few remaining (most taken from git fetch manpage; which is a bit dated in some places, unfortunately):

  • If remote-tracking branch (branch which tracks some branch in some remote repository) does not exists, it would be created.

  • The branch you fetch into (the <dst> in [+]<src>:<dst>) doesn't need to reside in remotes/<remote>/ namespace. For example for mirroring repositories ("git clone --mirror") refspec is 1 to 1. In old days before separate remotes layout (before remotes/<remote>/ namespace for remote-tracking refs) 'master' branch was fetched into branch called 'origin'. Even currently tags are fetched directly into tags/ namespace in mirroring fashion.

  • If branch you are fetching into (the right hand side of refspec <src>:<dst> does exist, Git would check if download would result in fast-forward, i.e. if current state in <dst> is ancestor of state in <src> in given remote repository. If it isn't, and you don't use -f / --force option to git-fetch, or prefix refspec with '+' (use +<src>:<dst> refspec) fetch would refuse to update that branch.

  • "git fetch origin master" is equivalent to "git fetch origin master:", not to "git fetch origin master:master"; it stores fetched value of 'master' branch (of remote ''origin') in FETCH_HEAD, and not in 'master' branch or remote-tracking 'remotes/origin/master' branch. It can be followed by "git merge FETCH_HEAD". Usually not used directly, but as part of one-time pull without setting remote-tracking branch: "git pull <URL> <branch>".

  • +refs/heads/*:refs/remotes/origin/* as value for "remote.origin.fetch" configuration variable means that each branch (ref in refs/heads/ namespace) in remote 'origin' is fetched into respectively named remote-tracking branch in refs/remotes/origin/ namespace, e.g. 'master' branch in 'origin' (i.e. 'refs/heads/master' ref) would be fetched into 'origin/master' remote-tracking branch (i.e. 'refs/remotes/origin/master' ref). The '+' prefix means that fetch would succeed even in non fast-forward case, which means when branch on remote is rebased, or rewound (reset to some state in past) or otherwise amended.

Sidenote: You would probably want to use higher level git remote command to manage remote repositories and get updates.

Jakub Narębski
Yes, "git remote update" is really handy, especially when you have multiple remotes.
Pat Notz
Hi Jakub, Thanks for the answer. In point #4 (para starting with "git fetch origin master"), you say that the remote repository will be stored in origin and not in remotes/origin/master. Is this because the command translates into "git fetch origin master:" which does not have a destination? Now if I want to merge the contents, then should I merge with FETCH_HEADS? Is this the correct way to fetch or should we ensure that the remote contents are fetched into the refs/remotes/origin/master?
Parag
@blog.adaptivesoftware.biz: I edited the answer to try to explain it better. Usually it is better workflow to set remote tracking branches (using "git remote add") when you plan fetching from remote more than once; "git pull <URL> <branch>" (and its git-fetch + git-merge equivalent) is used for one-time pulls.
Jakub Narębski
Hey Jakub, Thanks for editing the answer. It's clear now.
Parag