git pull真的是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并没有更新所有的远程跟踪分支。这是沙盒的缺陷还是git的实际情况?

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

谢谢!

似乎git pull并没有更新所有的远程跟踪分支。

这个可以发生,是的。当

例如,
  • git pull运行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存在之前实现了--fork-point模式的rebase(实际的--fork-point选项首次出现在Git 1.9中,但git pull从1.6版本开始做特殊的工作-我查了一次准确的版本,但这些天使用的最古老的Git似乎是CentOS,在一些发行版中包含一些Git 1.7版本)。
  • 有一个非常特殊情况:如果您创建一个空存储库,添加一个远程,并运行git pull,则还没有现有的分支。(稍后可以使用孤立分支再次触发这种情况。)在这种情况下,git pull运行一个专门的git checkout,而不是合并或重新base。

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

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

简而言之,是的。

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

配置变量决定的。如果你在真正的Git repo中运行git config remote.origin.fetch,你应该看到以下内容:

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

这称为refspec*告诉Git获取origin远程(:的右侧)中的所有分支,并将它们放入本地repo (:的左侧)。如果您运行git pullgit fetch而不带任何参数,那么由于此设置,所有新的和现有的远程跟踪分支将被更新。

来自文档:

运行git fetch时,没有指定分支和/或标签在命令行获取,例如git fetch origingit fetchremote.<repository>.fetch值被用作refspecs - they指定要获取哪些引用以及要更新哪些本地引用。的上面的例子将获取origin中存在的所有分支(即:任何匹配值左边的ref (refs/heads/*)并更新相应的远程跟踪分支refs/remotes/origin/*层次结构。

一旦你开始将分支名称传递给git pullgit fetch,这种行为就不再适用了,正如@torek在他的回答中指出的。

最新更新