1

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

您处于“分离 HEAD”状态。您可以环顾四周,进行实验性更改并提交它们,并且您可以放弃在此状态下所做的任何提交,而不会通过执行另一个签出来影响任何分支。

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

git 结帐 -b

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

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

我是否以某种方式破坏了我的树?我怎样才能找到这从哪里开始,以及如何解决它?

4

2 回答 2

3

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

那是因为这种git checkout是专门的 detach 请求HEAD

每当您使用不是分支名称但可以解析为提交哈希 ID 的东西时,git checkout都会将您置于 detached-HEAD 模式。但是任何时候你使用一个分支名称,都会git checkout让你进入正常模式。(Git 没有将此称为“attached-HEAD”模式,但这显然是该模式的正确名称。)

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

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

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

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

  • 使用该--track选项,您可以命名远程跟踪名称origin/developGit 将使用该名称来确定要创建的分支名称。Git 在这里选择的名称是通过剥离远程部分形成的,因此 running与 runninggit 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 说:Huh ... there's no branch nameddev和 no file-or-folder named 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 创建一个名为devnow 基于的分支origin/dev,你会得到一个令人讨厌的惊喜:Git(2.23 之前)会清除你对文件所做的任何工作dev/*


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

于 2020-05-12T06:24:34.057 回答
2

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

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

其次,当您签出 master 时,您正在切换到对分支 HEAD 提交的间接引用。
间接因为:

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

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

这就是我喜欢这个新git switch命令的原因:正如我在“为什么我的 Git repo 进入分离的 HEAD 状态? ”中解释的那样,它默认需要一个分支,而不是一个提交。更难最终得到一个不需要/意​​外的分离 HEAD。

于 2020-05-12T05:55:19.167 回答