为什么我的Git回购进入分离HEAD状态?

我结束了一个分离的头今天,同样的问题描述:git推送说所有最新的,即使我有本地更改

据我所知,我没有做任何不同寻常的事情,只是从本地回购中提交和推送。

那么我是如何以detached HEAD结束的呢?

319676 次浏览

任何不是你的分支名称的提交签出都会得到一个分离的HEAD。SHA1表示树枝的顶端,仍然给出一个分离的HEAD。只有签出本地分支的名字才能避免这种模式。

看到以独立的头脑进行承诺

当分离HEAD时,除了没有更新命名分支外,提交工作正常。(您可以将其视为一个匿名分支。)

alt text

例如,如果您结帐一个“远程分支”;如果不先跟踪它,你可能会得到一个分离的HEAD。

看到Git:没有分离头的开关分支

含义:git checkout origin/main(或origin/master在过去的日子)将导致:

Note: switching to 'origin/main'.


You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.


If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:


git switch -c <new-branch-name>


Or undo this operation with:


git switch -


Turn off this advice by setting config variable advice.detachedHead to false


HEAD is now at a1b2c3d My commit message

这就是为什么你不应该再使用git checkout,而应该使用新的git switch命令。

对于git switch,同样的尝试&;checkout&;(切换到)远程分支将立即失败:

git switch origin/main
fatal: a branch is expected, got remote branch 'origin/main'

git switch上添加更多内容:

在Git 2.23(2019年8月)中,你不再需要使用令人困惑的git checkout命令

git switch也可以签出一个分支,并获得一个分离的HEAD,除了:

  • 它有显式的--detach选项

在不创建新分支的情况下检出commit HEAD~3进行临时检查或试验:

git switch --detach HEAD~3
HEAD is now at 9fc9555312 Merge branch 'cc/shared-index-permbits'
  • 它不能错误地分离远程跟踪分支

看到的:

C:\Users\vonc\arepo>git checkout origin/master
Note: switching to 'origin/master'.


You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

Vs.使用新的git switch命令:

C:\Users\vonc\arepo>git switch origin/master
fatal: a branch is expected, got remote branch 'origin/master'

如果你想创建一个新的本地分支来跟踪一个远程分支:

git switch <branch>

如果没有找到<branch>,但在恰好一个远程(称其为<remote>)中存在一个具有匹配名称的跟踪分支,则将其等效于

git switch -c <branch> --track <remote>/<branch>

别再错了!
没有更多不想要的分离头!< / p >

如果你git switch <tag>而不是git switch --detach <tag>Git 2.36将帮助你记住缺少的--detach选项

如果您试图通过重新签出文件而撤消所做的更改,并且语法不完全正确,则很容易发生这种情况。

你可以看看git log的输出——你可以把上次成功提交后的日志尾部粘贴到这里,我们都可以看到你做了什么。或者你可以粘贴它并在freenode IRC的#git中询问。

我刚才无意中重复了这句话:

  1. 列出远程分支

    git branch -r
    origin/Feature/f1234
    origin/master
    
  2. I want to checkout one locally, so I cut paste:

    git checkout origin/Feature/f1234
    
  3. Presto! Detached HEAD state

    You are in 'detached HEAD' state. [...])
    

Solution #1:

Do not include origin/ at the front of my branch spec when checking it out:

git checkout Feature/f1234

解决方案2:

添加-b参数,用于从远程创建本地分支

git checkout -b origin/Feature/f1234

git checkout -b Feature/f1234它会自动回到原点

试一试

git reflog
这给出了你的HEAD和分支指针的历史

例如:

88ea06b HEAD@{0}: checkout:从开发移动到远程/原点/SomeNiceFeature e47bf80 HEAD@{1}:拉动原点DEVELOPMENT:快进

这个列表的顶部是一个原因,人们可能会遇到一个DETACHED HEAD 状态……

进入git分离头状态的另一种方法是尝试提交到远程分支。喜欢的东西:

git fetch
git checkout origin/foo
vi bar
git commit -a -m 'changed bar'

请注意,如果您这样做,任何进一步尝试签出origin/foo将使您回到分离的头部状态!

解决方案是创建自己的本地foo分支来跟踪origin/foo,然后可选地push。

这可能与您最初的问题无关,但该页在“git分离头”的谷歌次点击中排名靠前,这个场景的文档记录严重不足。

一个简单的偶然方法是将git checkout head作为HEAD的错别字。

试试这个:

git init
touch Readme.md
git add Readme.md
git commit
git checkout head

这给了

Note: checking out 'head'.


You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.


If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:


git checkout -b <new-branch-name>


HEAD is now at 9354043... Readme

如果您有一个与分支同名的标记,就会发生这种情况。

例如:如果“release/0.1”是标签名,那么

git checkout release/0.1

在“release/0.1”处产生分离的HEAD。如果您期望release/0.1是一个分支名称,那么您会感到困惑。

当你签出到一个提交git checkout <commit-hash>或一个远程分支时,你的HEAD将被分离,并尝试在它上创建一个新的提交。

任何分支或标记都无法访问的提交将在30天后被垃圾收集并从存储库中删除。

解决这个问题的另一种方法是为新创建的提交和签出创建一个新分支。git checkout -b <branch-name> <commit-hash>

本文将说明如何到达分离的头状态。

Detached HEAD表示当前签出的不是本地分支。

一些会导致Detached HEAD状态的场景:

  • 如果签出一个远程分支,则返回origin/master。这是一个只读分支。因此,当从origin/master创建一个提交时,它将是free-floating,即不连接到任何分支。

  • < p > 如果签出特定的标记或提交。当从这里进行新的提交时,它仍然是自由浮动,即不连接到任何分支。注意,当分支被签出时,新的提交总是自动放置在提示处。

    当你想要返回并签出一个特定的提交或标记以从那里开始工作时,你可以从该提交创建一个新的分支,并通过git checkout -b new_branch_name切换到它。这将防止Detached HEAD状态,因为你现在签出了一个分支,而不是提交。< / p >

如果 git 要重命名为 detached HEAD,我会把它命名为 一个没有被分支识别并且很快就会被遗忘的头

我们作为人很容易记住分支机构的名称。我们做 git checkout new-button-feature/git checkout mainmainnew-button-feature很容易记。我们可以做 git branch,得到所有分支的列表。但是要做同样的提交,你必须做 git reflog,这是非常乏味的。因为您有成千上万的提交,但只有很少的分支。

分离提交的标识符只是它的 SHA。所以假设你检出了一个提交(而不是一个分支) ,也就是说你检出了 git checkout d747dd10e450871928a56c9cb7c6577cf61fdf31,你会得到:

注: 检查 输出747dd10e450871928a56c9cb7c6577cf61fdf31’。

你处于“分离头部”状态。

...

然后,如果您做了一些更改并进行了提交,那么您仍然不在分支上。

你以为你还记得上诉委员会吗? 你不会记得的!

Git 不想这样。因此,它通知您的 HEAD 不与分支关联,所以您更倾向于签出一个新的分支。因此,在这条信息下面还写道:

如果要创建新的分支以保留所创建的提交,则 可以(现在或以后)通过再次使用-b 和 checkout 命令来完成。 例如:

Git checkout-b


再深入一点,分支的构建方式是明智的。它将在您提交时更新它的 HEAD。另一方面,标签不应该是这样的。如果你签出一个标签,那么你又在一个分离的头部。主要原因是,如果您从该标记进行了新的提交,然后给定该提交没有被任何东西(不是任何分支或标记)引用,那么它仍然被认为是一个分离的 HEAD。

只有当你在树枝上的时候才会有附着的头。

有关更多信息,请参见 给你

HEAD 是一个指针,它直接或间接地指向 特别承诺:

附加的 HEAD 意味着它附加到某个分支(即 指向树枝)。

分离的 HEAD 意味着它不连接到任何分支,即它 直接指向某个提交。

从另一个角度看,如果你在树枝上做 cat .git/HEAD,你会得到:

ref: refs/heads/Your-current-branch-name

然后,如果您执行 cat refs/heads/Your-current-branch-name,那么您还将看到您的分支所指向/引用的提交的 SHA。

然而,如果你在一个分离的头你和 cat .git/HEAD你只会得到 SHA 的提交,没有更多:

639ce5dd952a645b7c3fcbe89e88e3dd081a9912

我的意思是头部不指向任何分支,它只是直接指向一个提交。


因此,无论何时检出一个提交(不使用分支名称进行检出) ,即使该提交是 总台分支的最新提交,您都是分离的 HEAD 中的 还是,因为您的 HEAD 没有指向任何本地分支。因此,即使检查出一个标记将把你放在一个分离的头部。除此之外,即使检查了一个远程分支,你已经获取到您的计算机将导致一个分离的头即 git checkout origin main也将作为一个分离的头..。

摘要

以下所有情况都会导致头部分离:

  • 检查任何提交
  • 检查任何标签
  • 检查任何远程分支

如果你检查了 本地分支,你只是在一个连接的头上


特别感谢 Josh CaswellSaagar Jha帮助我解决这个问题。

对我来说,事情是这样的:

  • 创建一个新分支(feb _ debug)。
  • 运行 git fetch
  • 我看到新的分支(feb _ debug)被提出
  • 现在,我使用 git checkout origin/feb_debugging

在这里它让我头现在在... 。

我只是需要再检查一下

  • git checkout feb_debugging
  • 现在 git 说我在 feb _ debug 分支。

在 VonC 的评论之后,下面是我如何解决这个相同的“分离的 HEAD”问题的简短版本。

  1. 在我的遥控器中创建了一个分支; origin/feature/dev
  2. 在我的本地运行 git fetch,所以现在我的本地将知道这个新的远程分支
  3. 现在运行 git switch feature/dev,我们就完成了!

头部分离

HEAD是一个指向当前签出分支或提交的指针,它回答了这个问题: 我现在在存储库中的哪个位置 HEAD可以处于两种状态中的任意一种,附件(默认)或 分离,这取决于您是否签出了本地分支。

我是怎么得到 detached HEAD的?

操作比让 HEAD 处于分离状态

结束在 detached HEAD状态可能是由于各种原因,以下是5个常见的情况(也许你做了以下任何一个) :

  • 使用其散列检出特定的提交,即。
    $ git checkout 14ko3
    
  • 显式检出远程分支,即。
    $ git checkout origin/master
    
  • 使用分离标志(Git 2.23)切换到分支,即。
    $ git switch master --detached
    
  • 检查一个标签。
    $ git checkout v1.0.1
    
  • 执行交互式 rebase (或包含冲突更改的常规 rebase) ,即。
    $ git rebase master feature-1 --interactive
    

分离状态下,可以在不影响任何现有分支的情况下进行实验更改。请参阅下面的信息图,说明 committing在连接状态和分离状态之间的区别。

Comparison between detached and attached HEAD state

一个常见的误解是,消息 你处于“分离头部”状态的语气是错误的,而实际上它只是描述了 HEAD如何引用当前快照。

从分离状态到附着状态的移动

要从分离状态移动到附加状态,可以从所在位置创建新分支,或者切换回现有分支。

注意: 如果您切换到另一个现有的分支,在分离状态下创建的任何提交最终都将被丢弃(后垃圾收集) ,而不是首先在新分支中保存您的更改。

来源: 以上摘录自这篇关于这个主题的全文文章: 什么是 Git 中的 HEAD?

对于那些可能正在寻找获得分支机构名称的方法,但正在获得 HEAD的人来说,以下是我的想法:

const { execSync } = require('child_process');


const getBranchName = () => {
let branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
if (branch === 'HEAD') branch = execSync(`git branch -a --contains HEAD | sed -n 2p | awk '{ printf $1 }'`).toString().trim();
return branch;
}