Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having a hard time understanding git-fetch

Tags:

git

git-fetch

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, will it then 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 <options> <repository> <refspec> 

How would I use the refspec to fetch contents from my remote master into its remote tracking branch? I believe this may be possible if my current HEAD is on master and I run

git fetch origin master

However, can I use the <+?src:dest> refspec 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?

like image 526
Parag Avatar asked Jul 01 '09 17:07

Parag


People also ask

Does git pull fetch as well?

In the simplest terms, git pull does a git fetch followed by a git merge . git fetch updates your remote-tracking branches under refs/remotes/<remote>/ .

What's the difference between git fetch and git pull?

Git Fetch is the command that tells the local repository that there are changes available in the remote repository without bringing the changes into the local repository. Git Pull on the other hand brings the copy of the remote directory changes into the local repository.

What does git fetch do exactly?

The git fetch command downloads commits, files, and refs from a remote repository into your local repo. Fetching is what you do when you want to see what everybody else has been working on.

How do I use fetch in git?

When you do a git fetch, it fetches all the changes from the remote repository and stores it in a separate branch in your local repository. You can reflect those changes in your corresponding branches by merging. So basically, git pull = git fetch + git merge.


2 Answers

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.

like image 68
FelipeC Avatar answered Sep 24 '22 09:09

FelipeC


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.

like image 36
Jakub Narębski Avatar answered Sep 22 '22 09:09

Jakub Narębski