我怎么可能签出 Git 中不存在的分支?

How is it possible that I can checkout a non-existant branch in Git?

关于 Git 有很多我不知道的。我希望了解这是如何发生的:

是否git 找出合并点(分支合并时)并检查该提交?

git checkoutgit switch(在本例中做同样的事情)都内置了一个特殊功能。他们处理切换到类似于分支名称的字符串的请求的方式是这样的:

  1. 检查给定的字符串,例如 foofeature/branch-15a73c 是否已经存在 as 一个分支名称。如果是这样,那就是要签出的分支机构的名称。

  2. 检查是否可以将给定的字符串(例如 5a73c)转换为提交 的 有效哈希 ID。如果是这样,那就是 commit 作为一个分离的 HEAD 来检查。 (这里 git checkout 会这样做,而 git switch 会死于致命错误,除非你使用 --detach,在这种情况下它很好,也会这样做。)

  3. 假设我们已经走到这一步,如果 --guess 有效(见下文),请使用猜测代码。在 Git 的旧版本中,这称为“DWIM 模式”,其中 DWIM 代表 Do What I Mean。 (DWIM 有很长的历史可以追溯到 1960 年代的 Lisp,甚至在我使用计算机之前:我直到 1970 年代才开始接触硬件,然后才开始接触软件。)

--guess 选项在 commit ccb111b342f472d12baddbfa5b5281 中首次成为正式(并正确记录),在 Git 2.23.0 中首次发布,但由于它默认为 on 并且在此之前一直存在,除非您明确将其关闭,否则它会打开,这需要至少 2.23 的 Git 版本。所以它几乎总是开着。

它的工作方式是扫描您自己的存储库中的每个远程跟踪名称。这些名称是在 git fetch 时间创建和更新的,包括大多数 git fetch 操作 运行 通过 git pull 操作。默认情况下,它们 不会被删除 除非你明确地 运行 git fetch --prunegit remote prune,或者你特别使用 [=31] 的特殊情况=] 从您当前具有相应远程跟踪名称的远程删除分支。

您的远程跟踪名称是类似于 origin/fooorigin/feature/branch-1 的名称。你不太可能有一个 origin/5a73c 因为没有人会用它作为分支名称:你的远程跟踪名称是你的 Git 别人分支名称的副本,其他人会发疯的1 将其用作分支名称。但它可能会偶然发生,偶尔出现四个或更多字母的单词 2 完全由有效的十六进制数字组成:分支名称,例如 deedeffacefaded 可以在这里触发怪异。

无论如何,假设我们首先进入第 3 步(--guess 代码),Git 会扫描您的远程跟踪名称。您输入了,例如:

git checkout feature/branch-1

当你没有feature/branch-1分支时,第一步失败; feature/branch-1 无法转换为有效的哈希 ID,因为它包含非十六进制字符,例如 t 和正斜杠;所以我们到达第 3 步。Git 现在扫描您所有的 origin/* 名字:是其中之一 origin/feature/branch-1?

在这种情况下:是的,一个是。 Git 也会扫描所有 other 远程跟踪名称,例如 upstream/*,此时,找到 all考生。所有这些候选人的名单然后进入最后一组测试:

  • 列表是否为空?如果是,则猜测失败。

  • 列表是否恰好是一个元素长?如果是这样,那就是您希望 Git 猜测的远程跟踪名称。

  • 否则(列表中有多个条目),由于比赛之间的竞争,猜测失败,除非您使用Git2.19),checkout.defaultRemote。此功能让您可以选择“赢得”此类比赛的特定遥控器。

在这种情况下,您只得到一个匹配项: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 fetch -pgit remote prune 可能是明智的,甚至将 fetch.prune 设置为 true个人 Git 配置。否则,您可能会有很多陈旧的远程跟踪名称,并且人就是人,您为 您的 新功能发明的名称可能会与某人为 发明的旧名称发生冲突他们的 新功能。或者,代替那个教训,也许要采取的是禁用猜测(可能使用新的 Git-2.30 config.guess 设置)。注意,如果你想使用远程跟踪名称origin/foo创建本地分支foo,你可以输入:

git switch -t origin/foo

(隐含 -c foo 部分)。当然,这也适用于旧的 git checkout


1他们的疯狂可能有一种方法,或者只是他们方法的一种疯狂。

2最短的缩写 Git 将允许原始哈希 ID 为四个字符。因此,尽管分支名称 abc 由十六进制数字组成,但它绝不是提交哈希 ID。但是 abcd 有时是 提交哈希 ID。