如何修复Git分离的头部?

我正在我的存储库中做一些工作,注意到一个文件有本地更改。我不想再要它们了,所以我删除了文件,以为我可以签出一个新的副本。我想做相当于

svn up .

使用git pull似乎不起作用。一些随机搜索让我找到了一个有人推荐的网站

git checkout HEAD^ src/

src是包含已删除文件的目录)。

现在我发现我有一个分离的头。我不知道那是什么。我怎么能撤销?

2165469 次浏览

当你在git中签出一个特定的提交时,你最终会处于分离头状态……也就是说,你的工作副本不再反映命名引用的状态(如“master”)。这对于检查存储库的过去状态很有用,但如果你真的试图恢复更改,这不是你想要的。

如果您对特定文件进行了更改并且只想丢弃它们,您可以使用checkout命令,如下所示:

git checkout myfile

这将丢弃任何未提交的更改并将文件恢复到它在当前分支头部的任何状态。如果您想丢弃已经提交的更改,您可能需要使用reset命令。例如,这将把存储库重置为上一次提交的状态,丢弃任何后续更改:

git reset --hard HEAD^

但是,如果您与其他人共享存储库,则git reset可能会造成破坏(因为它会擦除存储库历史记录的一部分)。如果您已经与其他人共享了更改,您通常希望查看git revert,它会生成“反提交”-也就是说,它创建了一个“撤消”有问题的更改的新提交。

Git Book有更多细节。

分离的head意味着您不再在分支上,您已经签出了历史记录中的单个提交(在这种情况下,是HEAD之前的提交,即HEAD^)。

如果您想将与分离的HEAD关联的更改删除

你只需要检查你所在的分支,例如。

git checkout master

下次更改文件并希望将其恢复到索引中的状态时,先不要删除文件,只需执行

git checkout -- path/to/foo

这将把文件foo恢复到它在索引中的状态。

如果您想将与分离的HEAD关联的更改保持

  1. 运行git branch tmp-这将把您的更改保存在名为tmp的新分支中。
  2. 运行git checkout master
  3. 如果您想将您所做的更改合并到master中,请从master分支运行git merge tmp。运行git checkout master后,您应该在master分支上。

不创建临时分支的解决方案。

如何退出(“修复”)分离的HEAD状态当你已经在这个模式下改变了一些东西,并可选择保存您的更改:

  1. 提交您想要保留的更改。如果您想接管您在分离HEAD状态下所做的任何更改,请提交它们。比如:

    git commit -a -m "your commit message"
  2. Discard changes you do not want to keep. The hard reset will discard any uncommitted changes that you made in detached HEAD state:

    git reset --hard

    (如果没有这个,第3步将失败,抱怨分离的HEAD中修改了未提交的文件。)

  3. 看看你的分支。通过检查您之前处理的分支退出分离的HEAD状态,例如:

    git checkout master
  4. Take over your commits. You can now take over the commits you made in detached HEAD state by cherry-picking, as shown in my answer to another question.

    git refloggit cherry-pick <hash1> <hash2> <hash3> …

如果您更改了不想丢失的文件,您可以推送它们。我已在分离模式下提交它们,之后您可以移动到临时分支以稍后在master中集成。

git commit -m "....."git branch my-temporary-workgit checkout mastergit merge my-temporary-work

摘自:

如何处理在分离的头部中进行的提交

git pull origin master

为我工作。它只是明确地给出远程和分支名称。

这是我在意识到我是一个超然的头脑并且已经做了一些改变之后所做的。

我承诺了改变。

$ git commit -m "..."[detached HEAD 1fe56ad] ...

我记住了提交的哈希(1fe56ad)。然后我检查了我应该在的分支。

$ git checkout masterSwitched to branch 'master'

最后,我将提交的更改应用到分支。

$ git cherry-pick 1fe56ad[master 0b05f1e] ...

我认为这比创建临时分支要容易一些。

如果你做了更改,然后意识到你是一个分离的头,你可以这样做:stash->签主->stash pop:

git stashgit checkout master   # Fix the detached head stategit stash pop         # Or for extra safety use 'stash apply' then later#   after fixing everything do 'stash drop'

您将有未提交的更改和正常的“附加”HEAD,就像什么都没发生一样。

由于“分离的头部状态”将您放在临时分支上,只需使用git checkout -将您放在您所在的最后一个分支上。

增编

如果您希望返回的分支是您进行的最后一次签出,您可以简单地使用checkout @{-1}。这将带您回到上一次签出。

此外,您可以将此命令别名为git global --config alias.prev,例如,这样您只需键入git prev即可切换回上一个结帐。

分离头是指:

  1. 你不再在树枝上,
  2. 您已签出历史中的单个提交

如果您没有更改:您可以通过应用以下命令切换到master

  git checkout master

如果您想保留更改:

在分离的HEAD的情况下,像正常一样提交工作,除了没有命名分支得到更新。要使用已提交的更改更新主分支,请在您所在的位置创建一个临时分支(这样临时分支将拥有您在分离的HEAD中所做的所有已提交的更改),然后切换到主分支并将临时分支与主分支合并。

git branch  tempgit checkout mastergit merge temp

为了进一步澄清@Philippe Gerber的回答,这里是:

git chury-选择

cherry-pick之前,在这种情况下需要git checkout master。此外,在detached head中只需要commit

我想保持我的变化,所以,我只是解决这个做…

git add .git commit -m "Title" -m "Description"(so i have a commit now example: 123abc)git checkout YOURCURRENTBRANCHgit merge 123abcgit push TOYOURCURRENTBRANCH

这对我有用

Git告诉我怎么做。

如果您键入:

git checkout <some-commit_number>

保存状态

git add .git commit -m "some message"

然后:

 git push origin HEAD:<name-of-remote-branch>

处于“分离头”中意味着HEAD引用了特定的未命名提交(与命名分支相反)(参见:https://git-scm.com/docs/git-checkout部分分离头)。实际上,这意味着您已经签出了提交,但没有与之关联的分支名称。

您可以选择只创建与您的提交关联的新分支

git branch new-branch-name

这允许您将当前状态保存在名为new-branch-name的新分支中,而不再处于detached head状态。

或者,如果您想返回到上一个状态,则需要通过以下方式选择之前选择的分支

git checkout @{-1}

当您处于分离头的情况并创建新文件时,首先确保将这些新文件添加到索引中,例如:

git add .

但是,如果您只更改或删除了现有文件,您可以通过以下方式添加(-a)并同时使用消息(-m)提交:

git commit -a -m "my adjustment message"

然后,您可以简单地创建一个具有当前状态的新分支:

git checkout -b new_branch_name

你将有一个新分支,你所有的调整都将在该新分支中。然后,你可以继续推送到远程和/或签出/拉取/合并。

HEAD是一个指针,它指向-直接或间接-一个特定的提交:

HEAD表示它连接到某个分支(即它连接到一个分支)。
分离的HEAD意味着它是没有附加到任何分支,即它将直接指向某个提交。

在此处输入图片描述

换句话说:

  • 如果它指向提交直接,则HEAD为分离
  • 如果它指向一个提交间接(即它指向一个分支,该分支又指向一个提交),则HEAD为

为了更好地理解附加/分离HEAD的情况,让我们展示导致上面四重奏图片的步骤。

我们从存储库的相同状态开始(所有象限中的图片都是相同的):

在此处输入图片描述


现在我们想执行git checkout-在单个图片中使用不同的目标(它们上面的命令变暗以强调我们只是应用这些命令):

在此处输入图片描述


这是之后执行这些命令的情况:

在此处输入图片描述

如您所见,HEAD指向git checkout命令的目标-指向分支(四胞胎的前3个图像),或(直接)指向提交(四胞胎的最后一个图像)。

工作目录的内容也会根据适当的提交(快照)进行更改,即HEAD(直接或间接)指向的提交。


所以现在我们处于与答案开头相同的情况:

在此处输入图片描述

通常HEAD指向一个分支。当它不指向分支而是指向像69e51这样的提交哈希时,这意味着你有一个分离的HEAD。你需要将其指向两个分支来修复这个问题。你可以做两件事来修复它。

  1. git签出other_branch//当你需要提交hash中的代码时不可能
  2. 创建一个新分支并将提交哈希指向新创建的分支。

HEAD必须指向分支,而不是提交哈希是黄金法则。

分离的头意味着您没有正确签出您的分支,或者您刚刚签出了一个提交。

如果你遇到这样的问题,那么首先藏匿你的本地更改,这样你就不会丢失你的更改。

之后…使用命令签出您想要的分支:

假设你想要分支我的原创分支:

#获取当前版本git check out-b#删除当前版本

这对我有用,它将为分离的头部分配一个新的分支:

git checkout new_branch_name detached_head_garbage_name

你可能做了git reset --hard origin/your-branch

尝试git checkout your-branch

分离的HEAD意味着您当前不在任何分支上。如果您想保留当前的更改并简单地创建一个新分支,您可以这样做:

git commit -m "your commit message"git checkout -b new_branch

之后,您可能希望将此新分支与其他分支合并。git“一只狗”命令总是很有帮助:

git log --all --decorate --oneline --graph

意识到我有一个分离的头,而不知道我是如何设法得到它的(比如三次提交),我还发现尝试mergerebasecherry-pick触发了数百次合并冲突,所以我采取了不同的方法:

  1. (假设所有内容都已提交(工作树是“干净的”))

  2. 保存我的提交消息:git log > /tmp/log

  3. 保存我的工作树:mkdir /tmp/backup && cp -a all_my files_and_directories /tmp/backup

  4. 返回到mastergit checkout master

  5. 删除所有工作文件和目录:rm ...

  6. 使用备份:cp -a /tmp/backup/. .

  7. git addgit commit使用保存的/tmp/log中的消息,也许用不同的文件子集重复它…

缺点是,如果一个文件自master以来多次更改,您会丢失提交历史记录,但最终我有一个干净的master

这种方法可能会丢弃部分提交历史记录,但如果旧的master分支和当前状态的合并很棘手,或者您只是不介意丢失部分提交历史记录,则更容易。

要简单地保持当前状态,不合并,将当前分离的HEAD转换为master分支:

  1. 手动备份存储库,以防出现意外错误。
  2. 提交您想保留的最后更改。
  3. 创建一个临时分支(让我们将其命名为detached-head),它将包含当前状态的文件:
git checkout -b detached-head
  1. (a)删除主分支,如果您不需要保留它
git branch -D master
  1. (b)或重命名,如果你想保留它
git branch -M master old-master
  1. 将临时分支重命名为新的主分支
git branch -M detached-head master

信用:改编自加里·赖的这篇媒体文章

我也遇到过类似的情况
由于某种原因,我最终得到了一个分离的头-我在与我认为我所在的分支相同的路径上进行了提交-例如HEAD是分支标签的孩子,但由于某种原因,分支标签一直停留在历史提交……可能是因为我推了?

它不会让我推,因为我不被认为是在我认为我在的树枝上。

我不想改变我的任何历史或做任何樱桃采摘,我刚刚花了大约8周的时间在树枝上工作,所以reset --hard让我有点紧张!

解决方案只是做以下事情:

git branch -f myStuckBranch HEADgit checkout myStuckBranch

你需要做检查,即使HEAD和myStuckTree现在指向同样的事情,因为你仍然被认为是在分离的头状态(不是在一个分支)

我不是git专家(主要使用mercurial,它永远不会产生这种奇怪的情况),但我对这个命令的理解是,它只是说msgstr"将myStuck分支更改为指向HEAD"。

我经常发现自己在获取后使用此命令合并来自master的更改,而无需交换我的工作目录-否则它会尝试使用旧(无趣)版本的master:

git fetchgit branch -f master origin/master  -- err yeah don't just ignore what's been going on remotely - eg point my master at the real mastergit merge master -- merge the changes into my local branch

这是一个有点烦人的手动不得不这样做所有的时间,但仍然比不得不改变你的工作目录只是为了更新另一个分支,以合并从它的变化。

使用gitrebase,您可以将HEAD移动到所需的提交

假设你的分支处于分离状态,如下所示:

* bfcb8f9 Commit 4* 540a123 Commit 3* 4356d64 Commit 2| * fecb8d2 Commit 2|/| * 8012f45 Commit 2x|/| * 6676d15 (HEAD -> master) Commit 2 --amend|/* 1818f91 Commit 1

分离的头是通过错误地重新定位创建的,指向一个分离的提交,该提交是之前由于git提交--修改命令创建的。

如果您想将HEAD ref移动到最近的提交,请使用您要指向的所需HASH提交应用rebase。在此示例中,哈希是最新提交的:

git rebase bfcb8f9

这将使您的分支将其HEAD poting保留到所需的提交(在这种情况下是最近的):

* bfcb8f9 (HEAD -> master) Commit 4* 540a123 Commit 3* 4356d64 Commit 2 --amend| * fecb8d2 Commit 2|/| * 8012f45 Commit 2x|/| * 6676d15 Commit 2|/* 1818f91 Commit 1

添加到@ralphtheninja的答案中。如果您在使用git checkout master后收到此消息:

请在切换分支之前提交更改或隐藏它们。终止

然后,您可以简单地使用-f标志强制签出,如下所示:

git checkout -f master

显然,这将导致丢失在分离模式下所做的所有更改。所以在使用它时要小心。

当我开始使用git时,这对我来说是一件令人困惑的事情,后来我弄清楚了为什么会发生这种情况,以及处理这种情况的最佳方法是什么。

发生这种情况的根本原因是通常git HEAD总是指向某个分支,当您尝试将HEAD指向某个特定提交时,您将HEAD置于分离头状态。

当HEAD处于附加状态时-

cat .git/HEAD     # output--> ref: refs/heads/master or ref: refs/heads/main

当HEAD处于分离状态时-

cat .git/HEAD     # output--> b96660a90cad75867453ebe1b8d11754bbb68b0e <commit hash>

解决方案-

git stash           # Temporarily shelves (or stashes) changesgit branch          # Find your default branchgit switch master   # Point HEAD to master or main branchgit stash pop       # Apply all the changes you had previously

Git:您目前不在分支上。

时间到时间git显示:

将导致当前的历史推送(分离的HEAD)现在,使用

git push origin HEAD:<name-of-remote-branch>

它的意思是:

要修复此问题,请运行2个命令:

  1. git branch -f \{\{your_working_branch}} HEAD-设置分支到你的头
  2. git checkout \{\{your_working_branch}}--结帐==开关分支