TL;DR 总结
总的来说,我们对两三件事感兴趣:
- 如果您在没有其他参数的情况下运行
git fetch,会发生什么?
- 如果您在没有其他参数的情况下运行
git merge 或 git rebase,会发生什么?
- 如果您在没有其他参数的情况下运行
git pull,会发生什么?
对问题 #1 的简短回答是:Git 选择您的一个遥控器 进行获取,然后从该遥控器获取。远程 Git 选择来自 [branch] 部分下的 remote = <em>name</em> 设置。如果没有这样的设置,Git 使用origin。
问题 #2 的答案是:Git 选择一些要使用的名称,就像您运行过 git merge <em>name</em> 或 git rebase <em>name</em> 一样。 name 基于 merge = <em>ref</em> 设置在[branch] 部分下,但其工作方式有些模糊:例如,如果同一部分说、remote = origin 和branch = refs/heads/master,Git 选择使用的名称不是master,而是origin/master。如果它显示remote = origin 和branch = develop,则Git 选择的名称是origin/develop,依此类推。
(虽然这看起来很简单,但 Git 内部的实际映射相当棘手:例如,如果该部分显示 remote = . 和 branch = master,则名称是 master,而不是 ./master。如果您设置不寻常的 fetch refspecs,甚至可能发生更奇怪的事情。这个答案根本不包括最后一种情况。)
问题#3的答案在某些方面是最简单的:git pull首先运行git fetch,然后——如果成功的话——其他两个命令之一,git merge或git rebase,所以你真的只需要看问题 1 和 2。
长
我认为每个branch 部分下的merge 条目是最不明显的。 Git 文档使它有点晦涩难懂。让我们先介绍其他的。
[remote "..."] 部分下的设置
有许多可能的设置。通常,您不必直接使用git config 设置它们中的任何一个——几乎所有它们都有包装器命令以更“用户友好”的方式设置它们。这包括您在此处看到的两个设置。也很少想要改变这些。
每个命名远程的remote 部分(例如origin)列出了git fetch 的URL(以及可选的git push 的单独推送URL,以及其他remote.* 配置项为described in the git config documentation) .它还有一个或多个 fetch 行,它们为来自该远程的 git fetch 提供默认 refspec 参数。
也就是说,如果你运行:
git fetch origin
Git 将查找 remote.origin.url 以查看连接位置,然后在那里连接,然后根据所有 remote.origin.fetch 条目检索引用。您在此处看到的默认值:
+refs/heads/*:refs/remotes/origin/*
告诉 Git 从远程复制所有个分支1,将它们重命名为origin/-前缀远程跟踪分支2你自己的存储库,所以:
git fetch origin
基本上获取所有内容。 (前面的+表示无论远程跟踪分支更新是否是快进操作,Git都应该这样做。也就是说,它就像使用--force,但不必指定--force。)
另一方面,如果你运行:
git fetch origin a:b c:d
Git 将完全忽略所有fetch = 行,仅从远程检索引用a 和c,将它们写入您的存储库中的引用b 和d。 (而且由于这既没有+ 也没有--force,所以这些都不会被强制更新——尽管在大多数情况下这并没有什么区别。)
1, 2reference 是一个通用术语,涵盖分支 和 标签(以及更多内容)。像master 这样的分支名称只是以refs/heads/ 开头的引用的简写。像origin/master 这样的远程跟踪分支名称只是以refs/remotes/ 开头的引用的简写。请注意,origin/ 部分来自 fetch = 行,但要使所有这些按预期方式工作,该行必须与方括号中的遥控器名称匹配。
[branch "..."] 部分下的设置
有许多可能的设置。通常,您不必直接使用git config 设置它们中的任何一个——几乎所有它们都有包装器命令以更“用户友好”的方式设置它们。这包括您在此处看到的两个设置。使用我们稍后会看到的命令来更改其中一个或两个并不少见。
remote 部分本身非常清楚:这意味着如果您在分支 master 上并运行 git fetch 根本没有提供远程名称,Git 应该从名为 @987654389 的远程获取@。
merge 部分是棘手的部分。它列出了一个分支的名称在遥控器上可以看到。请注意,当我们运行 git fetch origin 时,我们告诉我们的 Git 调用另一个 Git,找到 另一个 Git 的 master,并将其复制到我们的存储库中,但将其命名为 origin/master。然而......这merge 行说merge = refs/heads/master。不应该说:merge = refs/remotes/origin/master吗?
它可能应该——但这种设置一开始就早于遥控器的发明。所以它没有;相反,它会列出参考的全名它出现在遥控器上。
如果您运行 git merge 或 git rebase 而不提供要合并或重新设置的分支名称,则会使用此设置。例如,Git 通过fetch = 行为远程提供的映射运行名称,以确定它应该与origin/master 合并。
git pull 便捷命令也使用此设置,这与运行 git fetch 后运行 git merge 的效果相同3。
您可能希望更改其中一项或两项。例如,如果您创建一个新的本地分支feature/tall,它可能根本没有branch.feature/tall.remote 和branch.feature/tall.merge 设置。
由于你刚刚创建了这个分支,所以没有origin/feature/tall。 origin 的 Git 还没有 feature/tall,所以你没有它的副本。
然后你 git push origin feature/tall:feature/tall 让你的 Git 调用 origin 的 Git 并让他们的 Git 创建那个分支,这样你现在做有 @987654412 @。您可能希望您的 Git 记住这一点。
您可以运行两个git config 命令,但是,您可以运行一个更高级别的包装器命令:
git branch --set-upstream-to=origin/feature/tall feature/tall
这告诉你的 Git 将 branch.feature/tall.remote 设置为 origin,并将 branch.feature/tall.merge 设置为 refs/heads/feature/tall(这是 origin 上的名称)。
您可以使用git push -u 组合git push 和git branch --set-upstream-to 步骤,这样会更好,但这里的重点仍然存在:您使用包装器同时设置两个值,因为只设置一个值并没有那么有用。4
特殊的远程名称. 表示此存储库(相对于某些远程存储库)。如果[branch "xyzzy"] 部分显示remote = . 和branch = refs/heads/whatever,则分支xyzzy 将local 分支whatever 作为其上游,而不是将origin/whatever 作为其上游。
3这故意掩盖了很多繁琐的细节。
4只设置remote 部分确实会影响未来的git push,但git merge 和git rebase 将无法进行远程操作- 跟踪没有两个条目的分支映射。