Git 在查看分支上的任何先前提交时开始分离头



我是一个较新的 git 用户,所以这可能是一个愚蠢的问题,但突然之间,每当我在Development分支中用类似git checkout 050aa9f的东西签出任何以前的提交时,git 都会立即分离头部:

您处于"分离的头部"状态。你可以环顾四周,做实验 更改并提交它们,您可以放弃在此所做的任何提交 通过执行另一个结帐来不影响任何分支的状态。

如果要创建一个新分支来保留您创建的提交,您可以 执行此操作(现在或以后),方法是再次将 -b 与 checkout 命令一起使用。例:

git 结帐 -b

HEAD 现在位于 050aa9f [代码提交标题在此处]

但是当我从另一个分支(例如master)签出提交时,它不会分离头部。

我是否做了什么以某种方式破坏我的树?我怎样才能找到它开始的地方,我该如何解决它?

每当我[使用]...git checkout 050aa9f......git 立即拆下头部

那是因为这种git checkout是专门要求分离HEAD

任何时候您使用不是分支名称但可以解析为提交哈希 ID 的内容时,git checkout都会将您置于分离 HEAD 模式。 但是,任何时候您使用分支名称,git checkout都会使您处于正常模式。 (Git 不称这种模式为"附加 HEAD"模式,但这是该模式的明显正确名称。

这里有几个棘手的问题,其中一些部分通过使用 VonC 推荐的新命令(在 Git 2.23 及更高版本中)git switch命令得到了部分帮助。 我将在这里介绍它们,但请记住,其中一些是高级 Git,您不需要立即了解所有内容。😀

  • Git 可以创建一个新分支,然后按名称检查该分支,从而生成附加的 HEAD。

  • 即使提供了分支名称,也可以使用带有分支名称的--detach来强制 Git 进入分离的 HEAD 模式。

  • 使用-b选项,Git 将始终尝试创建新的分支名称(然后附加到它)。 这在某些情况下可能会失败,尽管我不会在这里详细介绍。

  • 使用--track选项,您可以命名一个远程跟踪名称,例如origin/develop,Git 将使用该名称来确定要创建的分支名称。 这里 Git 选择的名称是通过剥离远程部分形成的,因此运行git checkout --track origin/develop与运行git checkout -b develop --track origin/develop大致相同。 我说的大致相同,因为其他选项可以修改此行为。

  • git checkout命令本身实现了在 Git 2.23 及更高版本中被拆分为两个单独的命令的内容:git switchgit restore。 在某些情况下,当您期望git checkout执行我将要描述的操作时,Git 会发现您有一个名为dev的文件或文件夹,并实现现在拆分为git restore的内容,而不是现在git switch的内容。 这是。。。不是一件好事,让我们这么说,从 Git 2.23 开始,git checkout现在告诉你,它不确定你在这里的意思,而不仅仅是做事。

  • 提供不存在但可以创建的分支的名称有时会导致创建该分支。 例如,如果你还没有一个名为dev的分支,但有一个origin/dev,并且你运行git checkout dev,你可能会期望 Git 说:呵呵......没有名为dev分支,也没有名为dev的文件或文件夹。 我不能把它变成一个分支名称,所以我会因错误而退出。但事实并非如此。 相反,Git 对自己说:呵呵,没有名为dev分支,也没有命名的文件或文件夹。 但是有一个origin/dev. 我敢打赌,您希望我创建一个名为dev的分支,就好像您运行了git checkout --track origin/dev一样。然后它就这样做了。


值得在这里准确描述旧git checkout出了什么问题,这与新git switch/git restore分裂有关。 (而且,正如我所提到的,git checkout本身已经变得更聪明,这样它现在就不会盲目地做错事——但对于早于 2.23 的 Git 版本,请注意!git checkout的两种"种类"是:

  • 切换分支的那个。 这是一个非破坏性命令:如果您有未提交的工作,git checkout可能会允许您切换分支,但只有当您未提交的工作在此过程中不会被销毁时,它才会这样做。 (这很复杂。 先别看,但这个问题就是关于这个的。

    在 Git 2.23 中,可以使用git switch来执行此命令。 您仍然可以使用git checkout,也可以。

  • 破坏
  • 你未承诺的工作的那个。 这是一个破坏性的命令! 假设你一直在编辑一些文件,并且你已经决定你试图做一些有用的事情是徒劳的,现在应该被彻底、不可逆转地销毁。 您希望将内容恢复原样 — 至少对于一个特定文件,也许对于多个文件

    。在 Git 2.23 中,您可以使用git restore来执行此命令,但在 Git 的每个版本中,您也可以在此处使用git checkout

这意味着一种git checkout是完全安全的:它永远不会破坏正在进行的工作。 另一种git checkout非常危险:你告诉 Git请清除我正在进行的工作,这是无法挽回的。

这就是我上面提到的危险。 假设您在一个名为dev的文件夹中有一堆文件,并且远程跟踪名称origin/dev,但您还没有名为dev的分支。 如果运行:

git checkout dev

期望 Git 基于origin/dev创建一个名为devNow 的分支,你会得到一个令人讨厌的惊喜:Git(2.23 之前)会清除你在dev/*文件上所做的任何工作。


(git checkout可以做更多的事情,所有这些现在都是拆分命令的一部分。 我省略了这些,以保持这个答案简短。 好吧,无论如何,更短。

因为当我签出我的主分支时,它不会创建一个分离的头

首先,确保使用git switch,这样您就可以确保处理分支或提交(结帐也处理文件,现在更好地使用git restore)

其次,当您签出主控时,您将切换到对分支 HEAD 提交的间接引用。
间接原因是:

  • .git/HEAD将包括"refs/heads/master
  • .git/refs/heads/master将包括实际的SHA1

与签出/切换提交相反,.git/HEAD直接包括 SHA1(无分支间接寻址)

这就是为什么我喜欢新的git switch命令:正如我在"为什么我的 Git 存储库进入分离的 HEAD 状态?"中所解释的那样,默认情况下它需要一个分支,而不是一个提交。很难最终得到一个不需要/意外的分离HEAD。

最新更新