Having a hard time understanding git
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,
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 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, ie 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, eg master branch in origin (ie refs/heads/master
ref) would be fetched into origin/master remote-tracking branch (ie 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 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
You often interact with the same remote repository by regularly and repeatedly fetching from it. In order to keep track of the progress of such a remote repository, git fetch
allows you to configure remote.<repository>.fetch
configuration variables.
Typically such a variable may look like this:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
This configuration is used in two ways:
When git fetch
is run without specifying what branches and/or tags to fetch on the command line, eg git fetch origin
or git fetch
, remote.<repository>.fetch
values are used as the refspecs---they specify which refs to fetch and which local refs to update .
The example above will fetch all branches that exist in the origin
(ie any ref that matches the left-hand side of the value, refs/heads/*
) and update the corresponding remote-tracking branches in the refs/remotes/origin/*
hierarchy.
When git fetch
is run with explicit branches and/or tags to fetch on the command line, eg git fetch origin master
, the <refspec>
s given on the command line determine what are to be fetched (eg master
in the example, which is a short-hand for master:
, which in turn means "fetch the ' master
' branch but I do not explicitly say what remote-tracking branch to update with it from the command line"), and the example command will fetch only the ' master
' branch.
The remote.<repository>.fetch
values determine which remote-tracking branch, if any, is updated.
When used in this way, the remote.<repository>.fetch
values do not have any effect in deciding what gets fetched (ie the values are not used as refspecs when the command-line lists refspecs); they are only used to decide where the refs that are fetched are stored by acting as a mapping.
下一篇: 很难理解git