git pull 真的是 git fetch + git merge 吗?

Is git pull really git fetch + git merge?

我在以下沙箱中练习 git:https://learngitbranching.js.org/?NODEMO

我 运行 在两个单独的会话中使用两组命令。第一组命令顺序如下:

git clone
git checkout -b feature
git push
git fakeTeamwork main 1
git fakeTeamwork feature 1
git pull

第二组命令顺序类似,但我在最后使用 git fetch + git merge

git clone
git checkout -b feature
git push
git fakeTeamwork main 1
git fakeTeamwork feature 1
git fetch
git merge o/feature

如果git pull = git fetch + git merge,为什么两个结果不同?似乎 git pull 没有更新所有远程跟踪 b运行ches。这只是沙盒的一个缺陷,还是 git 中实际发生的情况?

注意:命令 git clonegit fakeTeamwork 只是为沙盒构建的命令

谢谢!

It seems that git pull does not update all the remote tracking branches.

可以发生,是的。它 会在以下时间发生:

    例如
  • git pull 运行s git fetch origin master
  • git fetch origin master 因此只更新 origin/master.

此外,在 1.8.4 之前的 Git 版本中,某些 git fetch 操作根本不会更新任何远程跟踪名称。这里 git fetch origin masterorigin/master 没有影响。

除了这些,我们还有其他几个特例:

  • 如果 git pull 被配置或告知 运行 git rebase,它使用的第二个命令是 git rebase,而不是 git merge。因此,明显的替代是 git fetch 后跟 git rebase。不过,这里的一些细节甚至更多 Git 版本相关:特别是, git pullgit rebase --fork-point 存在之前为 rebase 实现了 --fork-point 模式(实际的 --fork-point 选项第一次出现在 Git 1.9,但 git pull 从某个 1.6 版本开始做特殊工作——我查过一次准确的版本,但最近使用的最老的 Git 似乎是 CentOS,在某些发行版中包含一些 Git 1.7 版本)。
  • 有一个非常的特殊情况:如果您创建一个空存储库,添加一个远程,并且运行 git pull,没有现有分支然而。 (稍后您可以使用孤立分支再次触发这种情况。)在这种情况下,git pull 运行 不是合并或变基,而是一个专门的 git checkout.

分支的 upstream 设置在这里很重要,具体取决于您传递给 git pull 或 fetch 和第二个命令的参数。一般来说,这些大多以相同的方式结束,除了你注意到的一些远程跟踪名称有时不会更新的警告。

Is git pull really git fetch + git merge?

简而言之,是的。

然而,值得指出的是 哪个 远程跟踪分支由 git fetch 更新(当调用时不带任何参数)由 remote.<repository>.fetch 决定配置变量。

如果您 运行 git config remote.origin.fetch 在真正的 Git 回购中,您应该看到以下内容:

+refs/heads/*:refs/remotes/origin/*

这叫做refspec* 告诉 Git 获取 origin 远程(: 的右侧)中的所有分支并将它们放入本地仓库(左侧 - : 的手边)。如果您 运行 git pullgit fetch 没有任何参数,所有新的和现有的远程跟踪分支都将由于此设置而更新。

来自documentation:

When git fetch is run without specifying what branches and/or tags to fetch on the command line, e.g. 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 (i.e. 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.

一旦您开始将分支名称传递给 git pullgit fetch,此行为将不再适用,如 @torek pointed out in