git checkout 和 git switch(在这种情况下做同样的事情)都内置了一个特殊功能。他们处理请求切换到类似于分支名称的字符串的方式是这样的:
-
检查给定的字符串,例如foo 或feature/branch-1 或5a73c,是否已经存在作为分支名称。如果是这样,那就是要签出的分支的名称。
-
检查给定的字符串,例如5a73c,是否可以转换为有效的提交哈希ID。如果是这样,那就是 commit 作为一个分离的 HEAD 检出。 (这里git checkout 会这样做,而git switch 会因致命错误而死,除非你使用--detach,在这种情况下它很好并且也会这样做。)
-
假设我们已经走到这一步,如果--guess 有效(见下文),请使用猜测代码。在旧版本的 Git 中,这称为“DWIM 模式”,其中 DWIM 代表按我的意思行事。 (DWIM 的悠久历史可以追溯到 1960 年代的 Lisp,甚至在我使用计算机之前:直到 1970 年代我才开始使用硬件和软件。)
--guess 选项首先在 commit ccb111b342f472d12baddbfa5b5281 中正式(并正确记录),首先在 Git 2.23.0 中发布,但由于它默认为 on 并且在此之前一直存在,所以除非您明确将其关闭,否则它需要至少 2.23 的 Git 版本。所以它几乎总是开启。
它的工作方式是扫描您自己的存储库中的每个远程跟踪名称。这些名称在git fetch 时间创建和更新,包括git pull 操作运行的大部分git fetch 操作。默认情况下,它们不会删除,除非您明确运行 git fetch --prune 或 git remote prune,或者在特殊情况下,您专门使用 git push 从您当前所在的远程删除分支有一个对应的远程跟踪名称。
您的远程跟踪名称是类似的名称,例如 origin/foo 或 origin/feature/branch-1。您不太可能拥有origin/5a73c,因为没有人会将其用作分支名称:您的远程跟踪名称是您的 Git 与其他人的分支名称的副本,而其他人会很疯狂1将其用作分支名称。但它可能会偶然发生,偶尔会出现完全由有效十六进制数字组成的四个或更多字母单词2:分支名称,如 deed 或 efface 或 faded 可能会在这里引发奇怪.
无论如何,假设我们首先进入第 3 步(--guess 代码),Git 会扫描您的远程跟踪名称。您输入的内容,例如:
git checkout feature/branch-1
当你没有feature/branch-1 分支时,所以第1 步失败; feature/branch-1 无法转换为有效的哈希 ID,因为它包含非十六进制字符,例如 t 和正斜杠;所以我们到了第 3 步。Git 现在扫描你所有的 origin/* 名称:是其中之一 origin/feature/branch-1?
在这种情况下:是的,一个是。此时,Git 还将扫描所有 其他 个远程跟踪名称,例如 upstream/*,以找到 所有 个候选对象。然后所有此类候选人的列表进入最后一组测试:
在这种情况下,您只得到了一个匹配项:origin/feature/branch-1。这使--guess 能够猜测,而不是:
git checkout feature/branch-1
你的意思是:
git checkout -b feature/branch-1 --track origin/feature/branch-1
这就是git checkout 所做的。 (虽然git switch 用-c 拼写,但git switch 在这里的行为方式相同,使用相同的控制旋钮:--guess 在命令行上,checkout.defaultRemote 用于处理模棱两可的多个匹配项。)
这里的一个潜在教训是,在您的个人 Git 配置中经常运行 git fetch -p 或 git remote prune 甚至将 fetch.prune 设置为 true 可能是明智之举。否则,您可能会有很多陈旧的远程跟踪名称,并且由于人是人,您为您的新功能发明的名称可能会与某人为他们的发明的旧名称发生冲突新功能。或者,代替那一课,也许要采取的方法是禁用猜测(也许使用 new-in-Git-2.30 config.guess 设置)。请注意,如果您想使用远程跟踪名称origin/foo 来创建本地分支foo,您可以输入:
git switch -t origin/foo
(隐含 -c foo 部分)。当然,这也适用于旧的 git checkout。
1他们的疯狂可能有一种方法,或者他们的方法可能只是一种疯狂。 ?
2Git 允许原始哈希 ID 的最短缩写是四个字符。因此,分支名称 abc 尽管由十六进制数字组成,但绝不是提交哈希 ID。但abcd 是有时是提交哈希 ID。