git pull命令输出信息含义到哪个分支

git pull command output message meaning into which branch

假设在远程仓库上有一个远程分支 br1 checkout,在本地仓库上有 master 分支。

我预计它也会显示类似“br1 -> master”的内容。为什么它不显示?

br1 -> br1”是指将远程 br1 拉入本地 br1 吗?

br1 -> origin/br1”是什么意思?

更新:在 VonC 的帮助下,我发现了以下内容:

更新 2:根据 torek 的解释,具体问题是命令 git pull origin br1:br1 将远程 br1 拉入 FETCH_HEAD 之后其他操作的顺序,然后将 FETCH_HEAD 合并到当前分支。

任何带有 origin/xxxx 的行表示 git pull (which is git fetch + git merge) has updated a remote tracking branchgit fetch 部分。
这是因为 git 1.8.4 (before it only updated FETCH_HEAD).

If I do just a "git pull", it will pull remote br1 into local master

这取决于 git config branch.b1.merge,它指示 git pull 的 git 合并部分进行合并。
通过执行 git pull b1:b1,您将覆盖该配置并指示合并在本地 b1 分支中进行。

另请参阅 git branch -avvv 的结果以了解哪个本地分支正在跟踪哪个远程分支。

I'm expecting it also shows something like "br1 -> master". Why it does not show that?

也许 master 已经在 97d4825

警告:长。 TL;DR 版本:您正在查看 git fetch 输出并且 git fetch 根本不会影响您的 master,影响的是 git pullgit merge 部分你的master。但是,您的 git fetch 正在更新远程跟踪 b运行ch origin/br1,并且在一种情况下更新甚至创建本地 b运行ch br1

git pull 是一个方便的脚本

永远记住 git pull 只是一个方便的脚本,运行 为您提供另外两个 git 命令:首先,git pull 将您的参数传递给 git fetch。完成后,git pull 运行s git merge(或者,如果指示,git rebase),但您原始问题中引用的所有操作都纯粹发生在 git fetch. ("update" 部分中的一点来自 git merge,稍后我会谈到。)

如果您没有向 git pull 提供 remote 参数,pull 脚本会从您当前的 b运行ch 配置中提取一个.在这种情况下,它提取的显然是origin。所以如果你 运行 git pull 没有指定 origin,你实际上是 运行ning git pull origin.

如果您没有为 git pull 提供 refspec 参数,pull 脚本会从您当前的 b[=389= 中提取一个非常简单的参数]ch 的配置——在这种情况下,无论你从 git config --get branch.master.merge 看到什么,它显然是 br1。所以这意味着如果你 运行 git pull origin,你实际上是 运行ning git pull origin br1.1

同样,所有这些都将传递给 git fetch,因此无论您是 运行、git pullgit pull origin 还是 git pull origin br1,所有那些只是结束调用:

git fetch origin br1

(你也可以手动完成,你会看到上面的)

我们稍后会在下面git fetch origin br1:br1

可能存在的误解的背景

让我们再次简要看一下您的设置语句:

Say there is a remote branch br1 checkout on the remote repo, and the master branch on a local repo.

什么 b运行ch,如果有的话,目前 checked-out 在遥控器上 mostlyfetchfetch 做的第一件事(或足够的第一件事)是连接到远程并向它请求所有引用及其对应的 SHA-1 的列表(你可以看到 git fetch 可以通过 运行宁 git ls-remote)。遥控器的 HEAD 包含在该列表中 ,这允许您指示 fetch 使用它,但如果您不这样做,您的 fetch 只是忽略它(遥控器的 HEAD 主要仅用于控制初始 git clone 上的默认初始 b运行ch)。

你的 local 仓库中的当前 b运行ch 很重要,但是有两个原因:

  • 如果您不向 git pull 提供额外的参数,它会根据您当前的 b运行ch 找到它们;和
  • fetch 成功后,git pull 运行s git mergegit rebase,它使用您当前的 b运行ch。

同样,您当前的 b运行ch 是 master,因此 pull 将使用 branch.master.remotebranch.master.merge 作为默认 remote refspec 参数。2 这就是我们如何从原始输出中推断出这些是 originbr1 分别。

git fetch

返回 git fetch,它所做的是与远程 git 服务器稍微协商一下,以找出哪些引用(b运行ches 和标签,主要是)可用以及它们对应的 SHA-1 值是什么。一旦获得该信息,它就会查看您要求它带来的参考资料。如果您列出了像 br1 这样的特定参考,那就是它会带来的参考。

当然,除了每个引用,它还必须带来任何新对象(提交本身及其关联的树和文件,以及任何父提交及其所需的树和文件),以便您获得从那个特定点开始的所有历史倒退。当然,无论您已经拥有什么历史记录,它都可以跳过。3

作为 ,git 在 git 上的行为 fetch <em>remote</em> <em>refspec</em> 在 git 1.8.4 及更高版本中发生了变化。过去是这样的,如果你 运行 git fetch <em>remote</em> <em>refspec</em>,您的 refspec 覆盖 您的 git 配置条目中的规则,但现在它只是 从中选择 。默认情况下,名为 origin 的遥控器的规则集是 +refs/heads/*:refs/remotes/origin/*,因此您的 br1 refspec 从该规则集中选择一个项目。


让我们暂停一下,看看如果您 运行 git fetch 只有 三个 个参数会发生什么,如下所示:

$ git fetch origin

这里你是在指示你的本地 git 连接到远程,找出它有什么,然后把 all b运行ches 带过来。它这样做的方式(和原因)就像上面概述的那样:它连接,获取一个列表,然后查询 git config --get-all remote.origin.fetch 的输出。4 这是一个列表"refspecs",每 git config --get-all 行一个。

由于 remote.origin.fetch 的标准行(单行)是 +refs/heads/*:refs/remotes/origin/*,您的本地 git 将采用匹配 refs/heads/* 的每个引用名称。也就是说,它将占用 origin 上的所有 b运行ches,因为 b运行ches 只是 "references whose names start with refs/heads/"。 对那些 b运行ches 所做的 由此 refspec 的右侧决定:它将 refs/heads/ 替换为 refs/remotes/origin/.

结果是"remote-tracking branch"。如果遥控器有一个 b运行ch master,您的本地 git t运行 会将其设置为 origin/master。如果遥控器有 br1,您的本地 git t运行 会将其设置为 origin/br1。对于远程上的每个 b运行ch,您都会得到一个(本地)远程跟踪 b运行ch,其名称以 origin/.5 开头


回到我们 git fetch origin br1 的例子,我们现在可以看到发生了什么:我们的本地 git 带来了 br1,结果是一个 b运行ch所以它的全名是refs/heads/br1。因此,它匹配标准 remote.origin.fetch 行并且 refs/heads/br1 被 t运行 指定为 refs/remotes/origin/br1,这导致 git 打印出 origin/br1 :

9188a5d..97d4825  br1        -> origin/br1

左边的名字br1是远程引用的简称,右边的​​名字origin/br1git fetch引用的简称已更新。

在过去,您会看到类似这样的内容,而且您仍然可能会看到它:

* branch            name       -> FETCH_HEAD

这表明 git fetch 在遥控器上找到了一个名为 name 的 b运行ch(即 refs/heads/name 形式的引用)并将其传送到您的本地 repo 并将其放入 FETCH_HEAD。什么是 FETCH_HEAD?这是一个特殊文件,几乎只为 git pull 脚本而存在。 (它的工作原理很像参考,但它具有特殊格式并且可能包含多个 SHA-1。)


现在我们(终于)准备好处理 br1:br1 案例了。在这里,您要告诉您的本地 git fetch 带来参考 br1。它像往常一样——调出遥控器,发现 br1 确实是 refs/heads/br1,并带来引用和任何需要的对象——但这一次,除了查阅 remote.origin.fetch 行,它将新的 SHA-1 写入指定的引用 you

在这种情况下,您指定的 br1 没有限定条件:不是 refs/heads/br1,不是 refs/remotes/origin/br1,只是 br1。在这种情况下,git 看到它是遥控器上的 refs/heads/ 引用,这意味着它是 b运行ch;所以 git 也会在你这边添加 refs/heads/,并创建或更新你自己的 refs/heads/br1.

换句话说,这会创建或更新您的 local b运行ch br1.

此外,git仍然应用remote.origin.fetch行,它仍然是+refs/heads/*:refs/remotes/origin/*,所以它仍然更新你的远程跟踪b运行ch origin/br1(全名refs/remotes/origin/br1)。 这就是您从命令 1 获得输出的原因。

git merge

FETCH_HEAD呢?好吧,这就是 git pull 的其余部分回归的地方:在完成 git fetch 步骤之后,pull 脚本 运行s git mergegit rebase.它合并(或 rebases-on-to)的是git fetch留在FETCH_HEAD文件中的任何东西(有一些特殊的外壳和其他我不会的警告'不要进入这里)。

当你当前的 b运行ch 是 master 但你指示 git pullorigin br1这是 git merge 步骤这使 masterbr1 同步。 更准确地说,合并使您在 git fetch 时与 origin/br1 的副本保持同步] 完成—可能就在您的 git fetch 完成后,其他人执行了 git push 更新了您遥控器上的 br1

如果可能,合并是 "fast-forward" 合并,但我不会在这里详细介绍。我只是注意到这是可能的,所以它已经完成了;那是更新中的 Fast-forward 行。

在任何情况下,合并为您当前的 b运行ch (master) 带来了自当前 b运行ch 和目标的合并基础以来的变化提交(git fetch 留在 FETCH_HEAD 文件中的原始 SHA-1,这也是 origin/br1 的新 SHA-1,并且在一种情况下,新的新 SHA-1 - 或更新本地 b运行ch br1).

在 git 的 1.8.4 之前版本中,origin/br1 远程跟踪 b运行ch 未更新。尽管如此,所有内容仍然可以在 FETCH_HEAD 文件中运行,而且,如果有的话,甚至比更新的 gits 更令人困惑 ,我们可以说你现在使用 origin/br1 是最新的,而不必对“br1 非常严格和挑剔,因为它在您 运行 git fetch 时在遥控器上”。

那个加号是什么?

眼尖的读者会注意到 +refs/heads/*:refs/remotes/origin/* 中的 +。这个 + 符号表示 "forced update"。通常,在更新 b运行ch 引用时——任何以 refs/heads/—git 开头的引用都不会 允许 更新,除非它是 "fast-forward" 标签更新。在 refspec 中设置强制标志允许特定更新。在命令行上使用 --force 也允许更新,所有其他参考更新也是如此。换句话说,加号只是 --force.

的更有针对性(单一 refspec)版本

1这是夸大其词:有时它使用三参数git fetch

2对于 remote 位始终为真,但 refspec 位可能为空,在 git fetch 完成后,使用 pull 脚本确定稍后应用哪个 refspec。

3默认情况下,fetch 操作还将带来与它带来的任何提交 ID 匹配的任何标记名称引用。如果你自己 运行 git fetch,你可以改变 fetch 处理这些的方式,但如果你只是让 git pull 运行 git fetch 你会得到这种默认行为。请注意,做出这些决定的是您的本地 git:远程 git 只是将所有内容显示到您的本地 git,然后您的 git 决定是否向您的存储库添加标签.

4技术上 git fetch 只是调用执行此操作的 C 代码,而不是实际上 运行ning git config --get-all。在任何情况下,如果 remote.origin.fetch 有多个配置条目,git fetch origin 确实会应用所有这些条目。虽然它的实现方式有点复杂,但我会跳过这里的血淋淋的细节。

5远程跟踪 b运行ches 实际上只是名称以 refs/remotes/ 开头的引用,就像本地 b运行ches是名称以 refs/heads/ 开头的引用。这是 git 中的普遍现象:您的标签是名称以 refs/tags 开头的引用。 git stash 脚本使用一个特殊的引用,refs/stash。 Git 的 "notes" 存储在 refs/notes/ 下,您可以发明自己的引用:只需选择不同的起始字符串,并希望以后没有其他人选择相同的字符串作为新 git 功能。 :-)