`git checkout -b newbranch upstream/newbranch` 和 `git checkout newbranch` 之间的区别

Difference between `git checkout -b newbranch upstream/newbranch` and `git checkout newbranch`

我已经阅读了 -bthis answer about importing an upstream branch into a fork. The answer suggests using git checkout -b newbranch upstream/newbranch to switch to the new branch. I always just used git checkout newbranch in this case and it worked aswell. Is there any difference between these commands? My guess is that I only need -b to specify a branch name in case it should be different from upstream/newbranch. But if I just want the branch with its original name newbranch, is there any difference between using git checkout -b newbranch upstream/newbranch and git checkout newbranch? I have read the docs,但这并没有真正回答我的问题。

-b命令创建一个新分支并签出。而 git checkout branch 检查一个已经存在的分支。请注意,如果您已经在本地跟踪了 newbranch,那么 git checkout -b newbranchgit checkout -b newbranch upstream/newbranch 将引发错误。

例如。假设您没有名为 random 的分支。然后下面报错:

git checkout random

但这会创建并检出 random:

git checkout -b random

相反,如果您有一个名为 random 的分支,第一个命令会将您切换到随机分支,而第二个命令将引发错误。

现有的答案没有确切它是如何工作的,这有点复杂。在内部,Git 调用这个东西 DWIM 模式

Long-ish: 背景

让我们从这个开始:您的分支名称是您的。其他一些 Git 可能有一个名为 newbranchbranch2 或其他名称的分支,但如果您没有该分支名称,您就没有该分支名称。好吧,还没有

还请记住,每个提交都有一个唯一的哈希 ID。要查看当前提交的哈希 ID,运行:

git rev-parse HEAD

特殊名称HEAD总是命名当前提交(通常也命名当前分支名称,但我们稍后再说)。 git rev-parse 命令会给你一个丑陋的大哈希 ID——对人类来说不是那么有用,但对 Git 至关重要,因为哈希 ID 是 Git 实际找到提交的方式。

同时,每个分支名称只包含一 (1) 个提交哈希 ID。如果你有一个分支名称master,你可以通过运行ninggit rev-parse master找到这个名称代表的哈希ID。和以前一样,git rev-parse 将名称变成丑陋的大哈希 ID。

现在,这意味着要创建一个 new 分支名称,您告诉 Git: 创建一个新的分支名称。这是要存储在其中的哈希 ID:_______。您告诉 Git 的 方法 是使用各种命令中的任何一个:

  • git 分支 <em>newname</em>:这告诉 Git 创建新名称使用通过将 HEAD 解析为哈希 ID 找到的哈希 ID。

  • git 分支 <em>newname</em> <em>hash-id</em>:这告诉 Git 使用您输入的散列 ID 创建新名称。散列 ID 很难输入,因此您可能会使用鼠标剪切和粘贴一个。但您不必这样做,因为:

  • git分支<em>newname</em><em>any-other-name-that-works-with-rev-parse</em>: Git 运行 git rev-parselast 名称上,找到哈希 ID,然后创建分支,使其包含你给它的哈希 ID。

  • git checkout -b <em>name</em> and git checkout -b <em>name</em> <em>start-point</em>:这些与使用 git branch 后跟 [= 非常相似330=]宁git checkout.

但是还有一种方法可以创建 new 分支名称,那就是 运行 git checkout <em>name-that-does-not-yet-exist</em>.

通常,如果您执行 git checkout supercalifragialistic 之类的操作,您只会得到一个错误:Git 尝试将该名称转换为哈希 ID(使用 git rev-parse 的内部等效项)这完全失败了,整个事情因错误而停止。但是 git checkout 内置了一个特殊的技巧。

现在,除了 branch names,Git 支持我称之为 remote-tracking names (Git 称它们为 remote-tracking 分支名称 但是这里的 branch 这个词有点误导,所以我认为最好保留它出去)。这些非常简单,真的:当你告诉它时,你的 Git 连接到其他 Git。您可能将其称为 Git origin,因为这是标准名称。您偶尔会 运行 git fetch origingit pull origin master 或类似的名称:名称 origin 这是您的 Git 找到 URL 用于调用的方式另一个 Git.

另一个 Git,在 origin,有分支名称。 你的 Git 记住他们的分支名称,但因为你的名字是你的,所以你的Git记住他们的别名。这些是 remote-tracking 个名字。您的 Git 将他们的 master 重命名为您的 origin/master,将他们的 xyz 重命名为 origin/xyz,依此类推。

在你的问题中你谈到了upstream/newbranch。名称 upstreamsecond Git 存储库的标准名称,您使用 git remote add 添加。你与之交谈的每个“其他Git”都有一个名字,remote-tracking名字有远程名字,后面是另一个Git' s branch 名称,它们之间有一个斜杠。所以你可能会同时得到 origin/newbranch upstream/newbranch,这很重要。

DWIM 模式

当你运行一个git checkout出错,因为你没有分支,git checkout会尝试一个新的在真正失败之前把戏。

您的 Git 将扫描 所有 个 remote-tracking 名称。例如,您可能有 origin/masterorigin/xyzupstream/xyzupstream/newbranch

如果你已经有一个 master 和 运行 git checkout master,那么 有一个 master,所以这是git checkout 将使用。但是如果你 运行 git checkout newbranch 并且没有新分支,Git 将扫描以上所有内容。只有 upstream/newbranch“看起来正确”,所以 Git 会自言自语:啊哈,如果我自动 create newbranchupstream/newbranch 现在,我可以将 切换为 它! 这就是它的作用: 创建 这是一个新的分支,然后切换到它。假设是当你说切换到现有分支newbranch时,你必须意味着创建新分支newbranch 来自 upstream/newbranch。 Git 做你想做的,而不是你说的。

请注意,如果您 运行 git checkout xyz,Git 有一个新问题:现在有 两个 候选人可以创建 xyz。它可以从 origin/xyzupstream/xyz 创建。默认情况下,DWIM 模式不会创建任何东西,您会看到错误。

(Git 2.21 及更高版本 --no-guess 可以完全禁用 DWIM。这主要用于 bash 完成脚本,如果你不想 Git猜测所有可能的 remote-tracking 个名字。)

其他几件重要的事情要知道

当你创建一个新的分支名称时,你可以Git设置它的upstream:

  • 每个分支名称要么有一个上游,要么没有上游。
  • 通常 master 的上游是 origin/master,例如。
  • 上游设置为您提供来自 git status 的更多信息,并让您 运行 git fetchgit mergegit rebasegit pull 无需再指定任何内容。所以这意味着方便。如果你觉得方便,就用它;如果没有,就不要。

要明确设置分支的上游,使用git branch --set-upstream-to;要删除上游,请使用 git branch --unset-upstream。当 git checkout 使用 DWIM 模式创建分支时,它通常会将该分支的上游设置为创建分支时使用的 remote-tracking 名称。您可以使用 git config 进行调整;参见 its documentation

当使用git branchgit checkout -b时,可以明确告诉Git是否设置newly-created分支的上游,使用-t--track 选项(这些是相同的选项:一个只是更长的拼写)。请注意,在同时具有 origin/xyz upstream/xyz 的棘手情况下,使用:

git checkout -t origin/xyz

是运行宁的short-hand方式:

git checkout -b xyz --track origin/xyz

也就是它:

  1. 指定在本地创建 xyz 时用于获取哈希 ID 的名称;
  2. 指定本地名称为xyz,因为使用的remote-tracking分支为origin/xyz;和
  3. 指定新本地 xyz 应设置为 origin/xyz 作为其上游。

使用 git checkout -t upstream/xyz 的工作方式类似,除了您的新 xyz 使用通过解析 upstream/xyz 找到的提交 ID 并且您的新 xyz 具有 upstream/xyz 作为它的上游。