我已阅读有关将上游分支导入 fork 的答案。答案建议使用git checkout -b newbranch upstream/newbranch
切换到新分支。我总是git checkout newbranch
在这种情况下使用它,它也很有效。这些命令之间有什么区别吗?我的猜测是我只需要-b
指定一个分支名称,以防它应该不同于upstream/newbranch
. 但是,如果我只想要具有原始名称的分支,那么使用andnewbranch
之间有什么区别吗?我已经阅读了文档,但这并没有真正回答我的问题。git checkout -b newbranch upstream/newbranch
git checkout newbranch
-b
2 回答
现有的答案并没有完全涵盖它是如何工作的,这有点复杂。在内部,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-point
git branch
git 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 origin
或git pull origin master
类似:origin
这里的名称是您的 Git 如何找到用于调用另一个 Git 的 URL。
位于 at 的其他 Gitorigin
具有分支名称。 你的Git 会记住它们的分支名称,但由于你的名字是你的,你的 Git 会以备用名称记住它们。这些是远程跟踪名称。你的 Git 将它们重命名master
为 your origin/master
,将它们重命名xyz
为origin/xyz
,依此类推。
在你谈到的问题中upstream/newbranch
。该名称upstream
是第二个Git 存储库的标准名称,您使用git remote add
. 您与之交谈的每个“其他 Git”都有一个名称,远程跟踪名称具有远程名称,后跟另一个 Git 的分支名称,它们之间有一个斜线。所以你可能会同时得到origin/newbranch
and upstream/newbranch
,这在下面很重要。
DWIM 模式
当您因为没有分支而运行会出错时,git checkout
将在git checkout
实际失败之前尝试一个新技巧。
您的 Git 将扫描您所有的远程跟踪名称。例如,您可能有origin/master
、origin/xyz
、upstream/xyz
和upstream/newbranch
。
如果你已经有一个master
and run git checkout master
,那么,你有一个master
,所以这就是git checkout
将使用的。但是如果你运行git checkout newbranch
并且没有新分支,Git 将扫描以上所有内容。只有upstream/newbranch
“看起来正确”,所以 Git 会对自己说:啊哈,如果我从现在开始自动创建,我可以切换 到它!newbranch
upstream/newbranch
这就是它的作用:将它创建为一个新分支,然后切换到它。假设是当你说切换到现有分支newbranch
时,你一定是指 从. Git 做你的意思,而不是你说的。newbranch
upstream/newbranch
请注意,如果您运行git checkout xyz
,Git 会遇到一个新问题:现在有两个候选者可以从中创建xyz
. 它可以从origin/xyz
或从创建upstream/xyz
。默认情况下,DWIM 模式不会创建任何内容,您会看到错误。
(Git 2.21 及更高版本必须--no-guess
完全禁用 DWIM。如果您不希望 Git 猜测所有可能的远程跟踪名称,这主要用于 bash 完成脚本。)
其他几个重要的事情要知道
当你创建一个新的分支名称时,你可以让 Git 设置它的上游:
- 每个分支名称要么有一个上游,要么没有上游。
- 例如,通常上游
master
为origin/master
。 - 上游设置为您提供来自 的更多信息
git status
,并允许您运行git fetch
、git merge
、git rebase
和 ,而git pull
无需再指定任何内容。所以它是为了方便。如果您觉得方便,请使用它;如果没有,不要。
要显式设置分支的上游,请使用git branch --set-upstream-to
; 要删除上游,请使用git branch --unset-upstream
. 当git checkout
使用 DWIM 模式创建分支时,通常会将该分支的上游设置为创建分支时使用的远程跟踪名称。您可以使用git config
; 请参阅其文档。
使用git branch
or时,您可以使用or选项git checkout -b
明确告诉 Git 是否设置新创建分支的上游(这些是相同的选项:一个只是一个更长的拼写)。请注意,在同时具有和的棘手情况下,使用:-t
--track
origin/xyz
upstream/xyz
git checkout -t origin/xyz
是一种简写的运行方式:
git checkout -b xyz --track origin/xyz
这就对了:
xyz
指定在本地创建时用于获取哈希 ID 的名称;- 指定本地名称是
xyz
因为使用的远程跟踪分支是origin/xyz
; 和 - 指定
xyz
应将新本地设置origin/xyz
为其上游。
Usinggit checkout -t upstream/xyz
的工作方式类似,除了您的 newxyz
使用通过解析找到的提交 IDupstream/xyz
并且您的 newxyz
具有upstream/xyz
作为其上游。
该-b
命令创建一个新分支并将其签出。而git checkout branch
检查一个已经存在的分支。请注意,如果您已经在newbranch
本地进行了跟踪,那么git checkout -b newbranch
或git checkout -b newbranch upstream/newbranch
将引发错误。
例如。假设您没有名为random
. 然后以下给出错误:
git checkout random
但这会创建并签出random
:
git checkout -b random
相反,如果您有一个名为random
第一个命令的分支,则会将您切换到随机分支,而第二个将引发错误。