首页 > 解决方案 > `git checkout -b newbranch upstream/newbranch` 和 `git checkout newbranch` 之间的区别

问题描述

我已阅读有关将上游分支导入 fork 的答案答案建议使用git checkout -b newbranch upstream/newbranch切换到新分支。我总是git checkout newbranch在这种情况下使用它,它也很有效。这些命令之间有什么区别吗?我的猜测是我只需要-b指定一个分支名称,以防它应该不同于upstream/newbranch. 但是,如果我只想要具有原始名称的分支,那么使用andnewbranch之间有什么区别吗?我已经阅读了文档,但这并没有真正回答我的问题。git checkout -b newbranch upstream/newbranchgit checkout newbranch-b

标签: gitgit-branchgit-checkoutgit-forkupstream-branch

解决方案


现有的答案并没有完全涵盖它是如何工作的,这有点复杂。在内部,Git 将这个东西称为 DWIM 模式

长篇:背景

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

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

git rev-parse HEAD

特殊名称HEAD总是命名当前提交(并且通常也命名当前分支名称,但我们稍后会保留它)。该git rev-parse命令将为您提供丑陋的大哈希 ID — 对人类来说不是那么有用,但对 Git 至关重要,因为该哈希 ID 是 Git 实际查找提交的方式。

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

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

  • git branch newname:这告诉 Git 使用通过解析HEAD为哈希 ID 找到的哈希 ID 创建新名称。

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

  • git branch newname any-other-name-that-works-with-rev-parse:这让 Gitgit rev-parse姓氏上运行,以查找哈希 ID,然后创建分支以使其包含您给它的哈希 ID。

  • git checkout -b name和:这些与 using其次是 running非常相似。git checkout -b name start-pointgit branchgit checkout

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

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

现在,除了分支名称之外,Git 还支持我称之为远程跟踪名称的东西(Git 称它们为远程跟踪分支名称,但这里的分支这个词有点误导,所以我认为最好不要使用它)。这些非常简单,真的:当你告诉它时,你的 Git 会连接到其他 Git。您可能称它为另一个 Git origin,因为这是标准名称。您偶尔会运行git fetch origingit pull origin master类似:origin这里的名称是您的 Git 如何找到用于调用另一个 Git 的 URL。

位于 at 的其他 Gitorigin具有分支名称。 你的Git 会记住它们的分支名称,但由于你的名字是你的,你的 Git 会以备用名称记住它们。这些是远程跟踪名称。你的 Git 将它们重命名master为 your origin/master,将它们重命名xyzorigin/xyz,依此类推。

在你谈到的问题中upstream/newbranch。该名称upstream第二个Git 存储库的标准名称,您使用git remote add. 您与之交谈的每个“其他 Git”都有一个名称,远程跟踪名称具有远程名称,后跟另一个 Git 的分支名称,它们之间有一个斜线。所以你可能会同时得到origin/newbranch and upstream/newbranch,这在下面很重要。

DWIM 模式

当您因为没有分支而运行会出错时,git checkoutgit checkout实际失败之前尝试一个新技巧。

您的 Git 将扫描您所有的远程跟踪名称。例如,您可能有origin/masterorigin/xyzupstream/xyzupstream/newbranch

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

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

(Git 2.21 及更高版本必须--no-guess完全禁用 DWIM。如果您不希望 Git 猜测所有可能的远程跟踪名称,这主要用于 bash 完成脚本。)

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

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

  • 每个分支名称要么有一个上游,要么没有上游。
  • 例如,通常上游masterorigin/master
  • 上游设置为您提供来自 的更多信息git status,并允许您运行git fetchgit mergegit rebase和 ,而git pull无需再指定任何内容。所以它是为了方便。如果您觉得方便,请使用它;如果没有,不要。

要显式设置分支的上游,请使用git branch --set-upstream-to; 要删除上游,请使用git branch --unset-upstream. 当git checkout使用 DWIM 模式创建分支时,通常会将该分支的上游设置为创建分支时使用的远程跟踪名称。您可以使用git config; 请参阅其文档

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

git checkout -t origin/xyz

是一种简写的运行方式:

git checkout -b xyz --track origin/xyz

这就对了:

  1. xyz指定在本地创建时用于获取哈希 ID 的名称;
  2. 指定本地名称是xyz因为使用的远程跟踪分支是origin/xyz; 和
  3. 指定xyz应将新本地设置origin/xyz为其上游。

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


推荐阅读