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:
Can it be possible that a local tracking branch does not exist? If so, will it then be created automatically?
What will happen if I do a
fetch
and specify a non tracking branch as the destination?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?
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,
That means if you do
It will actually do:
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 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 inremotes/<remote>/
namespace. For example for mirroring repositories (git clone --mirror
) refspec is 1 to 1. In old days before separate remotes layout (beforeremotes/<remote>/
namespace for remote-tracking refs) master branch was fetched into branch called origin. Even currently tags are fetched directly intotags/
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 togit fetch origin master:
, not togit fetch origin master:master
; it stores fetched value of master branch (of remote origin) in FETCH_HEAD, and not in master branch or remote-trackingremotes/origin/master
branch. It can be followed bygit 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 inrefs/heads/
namespace) in remote origin is fetched into respectively named remote-tracking branch inrefs/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.
Note also that, with Git 2.5+ (Q2 2015),
git merge FETCH_HEAD
can merge multiple git fetch's.See commit d45366e by Junio C Hamano (
gitster
), 26 Mar 2015.(Merged by Junio C Hamano --
gitster
-- in commit bcd1ecd, 19 May 2015)The
git merge
doc now mention:Git 2.13 (Q2 2017) officially retires the old syntax for
git merge
.See commit b439165 (26 Mar 2015) by Junio C Hamano (
gitster
).(Merged by Junio C Hamano --
gitster
-- in commit 1fdbfc4, 30 Mar 2017)That means the warning message old-style "
'git merge <msg> HEAD <commit>' is deprecated.
" is no more.Note that the main maintainer for Git has now (Git 2.1, August 2014) added this explanation for
git fetch
:(See commit fcb14b0 by Junio C Hamano (
gitster
):CONFIGURED REMOTE-TRACKING BRANCHES