问题
Here's the contents of the remote
and branch
sections of my .git/config
file.
[remote "origin"] url = https://EvanAad@bitbucket.org/EvanAad/bitbucketstationlocations.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master
What is the meaning and purpose of the contents of these sections, in particular the fetch
and merge
subsections? How is this information used by Git to guide its operation?
回答1:
Its called refspec. Its the mechmism that git is using to "talk" to the remote server and to map local branches to remote branches.
Refspecs
A refspec maps a branch in the local repository to a branch in a remote repository.
This makes it possible to manage remote branches using local Git commands and to configure some advanced git push and git fetch behavior.
A refspec is specified as [+]<src>:<dst>
. The <src>
parameter is the source branch in the local repository, and the <dst>
parameter is the destination branch in the remote repository.
The optional +
sign is for forcing the remote repository to perform a non-fast-forward update.
Refspecs can be used with the git push command to give a different name to the remote branch. For example, the following command pushes the master branch to the origin remote repo like an ordinary git push, but it uses qa-master as the name for the branch in the origin repo. This is useful for QA teams that need to push their own branches to a remote repo.
git push origin master:refs/heads/qa-master
By adding a few lines to the Git configuration file, you can use refspecs to alter the behavior of git fetch.
By default, git fetch
fetches all of the branches in the remote repository. The reason for this is the following section of the .git/config
file:
[remote "origin"]
url = https://git@github.com:mary/example-repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
The fetch
line tells git fetch to download all of the branches from the origin repo.
But, some workflows don’t need all of them. For example, many continuous integration workflows only care about the master branch. To fetch only the master branch, change the fetch line to match the following:
[remote "origin"]
url = https://git@github.com:mary/example-repo.git
fetch = +refs/heads/master:refs/remotes/origin/master
You can also configure git push in a similar manner. For instance, if you want to always push the master branch to qa-master in the origin remote (as we did above), you would change the config file to:
[remote "origin"]
url = https://git@github.com:mary/example-repo.git
fetch = +refs/heads/master:refs/remotes/origin/master
push = refs/heads/master:refs/heads/qa-master
Refspecs give you complete control over how various Git commands transfer branches between repositories.
They let you rename and delete branches from your local repository, fetch/push
to branches with different names, and configure git push and git fetch to work with only the branches that you want.
回答2:
The merge
entry under each branch
section is, I think, the least obvious. The Git documentation keeps it a bit obscure. Let's cover the others first.
Settings under a [remote "..."]
section
There are many possible settings. In general, you do not have to set any of them with git config
directly—almost all of them have wrapper commands to set them in a more "user friendly" manner. That includes both of the settings you see here. It's rare to want to change these, either.
The remote
section for each named remote, such as origin
, lists the URL for git fetch
(and optionally a separate push URL for git push
, and other remote.*
configuration items as described in the git config documentation). It also has one or more fetch
lines which supply the default refspec arguments for git fetch
from that remote.
That is, if you run:
git fetch origin
Git will look up remote.origin.url
to see where to connect, then connect there, then retrieve references based on all the remote.origin.fetch
entries. The default that you see here:
+refs/heads/*:refs/remotes/origin/*
tells Git to copy all branches1 from the remote, renaming them to an origin/
-prefixed remote-tracking branch2 in your own repository, so:
git fetch origin
basically fetches everything. (The leading +
says that Git should do this regardless of whether the remote-tracking branch update is a fast-forward operation. That is, it's like using --force
, but without having to specify --force
.)
On the other hand, if you run:
git fetch origin a:b c:d
Git will completely ignore all the fetch =
lines, retrieving only references a
and c
from the remote, writing them to references b
and d
in your repository. (And since this has neither +
nor --force
, none of these will be force-updated—though in most cases that makes no difference anyway.)
1, 2 A reference is a generic term that covers both branches and tags (and more things as well). Branch names like master
are just short-hand for references that begin with refs/heads/
. Remote-tracking branch names like origin/master
are just short-hand for references that begin with refs/remotes/
. Note that the origin/
part comes from the fetch =
line—but for all this to work the way it is supposed to, that line must match the name of the remote in the square brackets.
Settings under a [branch "..."]
section
There are many possible settings. In general, you do not have to set any of them with git config
directly—almost all of them have wrapper commands to set them in a more "user friendly" manner. That includes both of the settings you see here. It's not that rare to want to change one or both of them, using a command we will see in a moment.
The remote
part is pretty clear on its own, though: it means that if you are on branch master
and run git fetch
without giving a remote name at all, Git should fetch from the remote named origin
.
The merge
part is the tricky one. It lists the name of a branch as seen on the remote. Note that when we run git fetch origin
, we tell our Git to call up another Git, find the other Git's master
, and copy that into our repository but call it origin/master
. And yet ... this merge
line says merge = refs/heads/master
. Shouldn't it say: merge = refs/remotes/origin/master
?
It probably should—but this setting predates the very invention of remotes in the first place. So it doesn't; instead, it lists the full name of the reference as it appears on the remote.
This setting is what gets used if you run git merge
or git rebase
without providing a branch name to merge or rebase-upon. Git runs the name through the mappings provided by the fetch =
line for the remote, to figure out that it should merge with origin/master
, for instance.
This setting is also used by the git pull
convenience command, which is effectively3 the same as running git fetch
followed by running git merge
.
You might want to change one or both of these. For instance, if you create a new local branch feature/tall
, it may have no branch.feature/tall.remote
and branch.feature/tall.merge
settings at all.
Since you just created this branch, there is no origin/feature/tall
. The Git over at origin
does not have feature/tall
yet, so you do not have a copy of it.
Then you git push origin feature/tall:feature/tall
to have your Git call up origin
's Git and have their Git create that branch, so that you now do have origin/feature/tall
. You might want your Git to remember that.
You could run two git config
commands, but instead, you can run one higher level wrapper command:
git branch --set-upstream-to=origin/feature/tall feature/tall
This tells your Git to set branch.feature/tall.remote
to origin
, and branch.feature/tall.merge
to refs/heads/feature/tall
(that being the name on origin
).
You can combine the git push
and the git branch --set-upstream-to
steps using git push -u
, which is even better, but the point here remains: you use a wrapper to get both values set at once, since setting only one value is not that useful.4
3This deliberately glosses over a lot of fiddly details.
4Setting just the remote
part does affect a future git push
, but git merge
and git rebase
won't be able to do the remote-tracking branch mapping without both entries.
来源:https://stackoverflow.com/questions/43317872/understanding-git-configs-remote-and-branch-sections