git pull --rebase 原始标记名?

git pull --rebase origin tagname?

我正在研究一些使用 git 的生产脚本,并试图理解这个命令:

git pull --rebase origin "${tag_or_commit}"

根据我在 git pullgit rebase 的文档中找到的内容,看起来 ever 唯一应该 tag_or_commit bash 变量,必须是命令才能工作的分支名称。

在给定标记或提交而不是分支的情况下,是否有关于此命令将执行的操作的记录行为?我在哪里可以找到它?

标签和分支实际上只是对提交的引用,主要区别在于分支指的是移动目标(该分支上的最新提交),而标签引用单个时间点提交,但最终他们只是指向一个提交。

上面的 tag_or_commit 变量可以重命名为 tag_or_branch_or_commit,或简称为 commit。我认为变量名称有点误导/混淆。

我发现最常见的用法是将其变基以提供分支,这意味着将分支变基到最近的提交。提供提交(或标记)将变基到该提交,不再进一步。

所以上面的完整命令是从原点拉取,然后重新设置 tag_or_commit 所指点之前发生的提交。一个用例可能是,如果你想变基到已发布到生产环境的内容,并且你有一个标签 production_release,那么如果你要执行:

git pull --rebase origin production_release

您将获得直到 production_release 标记的所有提交,但不会更多。

编辑:根据您对上一个答案的评论,您只遗漏了一件事:git rebase 步骤变基 当前分支,无论您传递给 git pull 的参数是什么。您可以跳过所有其他内容!


它实际上在 the git pull documentation 中,但在典型的 git 文档格式中,让人格外困惑:

<refspec> can name an arbitrary remote ref (for example, the name of a tag) or even a collection of refs with corresponding remote-tracking branches (e.g., refs/heads/*:refs/remotes/origin/*), but usually it is the name of a branch in the remote repository.

缺少的是 "refspec" 的完整定义以及 git pull 运行 的两个部分的完整描述。不幸的是,对于第一部分,refspecs 出现在 fetch 和 push 中,但在它们中表现不同。可以这么说,为了获取目的,通常您只需命名远程上存在的分支或标签,然后 git fetch 将其复制到您自己的存储库,但将名称更改为远程跟踪分支,例如 origin/master, 如果是分支。对于标签,它保留名称不变。 (更准确地说,来源的 refs/heads/master 在您的存储库中变为 refs/remote/origin/master,而其 refs/tags/v1.2 保持 refs/tags/v1.2。)

第二部分可能更容易一些:git pull 收集一些标志并自己对其进行操作,然后将其余部分传递给第一步,git fetchgit pull 收集的标志之一是 --rebase,它告诉它使用 git rebase 作为其第二步。否则,它会查看是否已配置为自动使用 git rebase;如果没有,它默认使用 git merge.

在这种情况下,那么,给定标签名称taggit pull将:1

  1. 运行 git 获取来源 <em>标签</em>
  2. 运行 git 变基 <em>tag</em>

如果需要,获取步骤将创建一个本地标签,如果需要,获取任何相应的提交和其他对象,或者如果您已经拥有标签,则只是一个美化的空操作。

第二步是特别令人困惑的一点。将标签名称传递给 git rebase 作为其 "upstream" 参数似乎很奇怪。但是,它定义明确并且有意义;这在 the git rebase documentation 中也有相当详细的描述,前提是您知道 rebase 的秘密:它不会 更改 任何提交,它只是 复制 一些提交,然后重新指向您当前的分支。

首先,git 获取当前分支中包含的提交列表,2 不包括可从指定上游访问的任何提交:

$ git rev-list tag..HEAD

接下来,git 进入一个新的匿名分支,该分支从 --onto 参数标识的提交开始,或者如果没有 --onto,则从 [= 标识的提交开始125=] 参数。在这种情况下,没有 --onto 并且 "upstream" 参数是一个标签,因此 git 可以简单地检查标签(它不完全是 - 它使用适用于分支名称也是如此——但结果是一样的)。

作为倒数第二个步骤,rebase "replays" 每个 ID 在 git rev-list 输出中的提交。本质上,git cherry-picks 每个这样的提交到新的匿名分支中。

作为最后一步(如果一切顺利,或者在您修复并完成 git rebase --continue 之后),git 移动您所在的分支3 指向通过复制所有要复制的提交所做的最终提交。假设您在某个分支上起源于某个地方 "before" 标记的提交 T,因此我们可以绘制最终结果的图表,如下所示:

    A - B - C            [abandoned]
  /
o - o - T - o - o         <-- somebranch
          \
           A' - B' - C'   <-- HEAD=yourbranch

这里 AC 是您在 yourbranchgit pull origin <em> 标签[之前的原始提交=104=]步,A'C'是他们的副本。


1这仍然是简化的,并且git pull随着时间的推移而发展;实际的论点可能会变得非常复杂。幸运的是,None 对于这种特殊情况很重要。

2如果您根本不在任何分支上,这甚至可以工作:在这种情况下,git 使用由 [ 中的任何提交 ID 定义的匿名分支=45=].

3如果你不在一个分支上,那就更简单了:它完全跳过了这一步。 HEAD 仍然指向匿名分支,但现在是复制的分支。