ChatGPT解决这个技术问题 Extra ChatGPT

如何修复 Git 分离头?

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

svn up .

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

git checkout HEAD^ src/

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

现在我发现我有一个分离的头。我不知道那是什么。我该如何撤消?

git checkout master 会让您回到主分支。如果您想清除任何工作副本更改,您可能需要执行 git reset --hard
如果您还没有承诺,您可以完成git checkout -- src/
试试这个:link。总之create temp branch - checkout temp branch - checkout master - delete temp branch
@AbeVoelker 您在 working copy changes 的评论中是什么意思?您是指在签出另一个提交后对文件所做的更改(即,您在分离头状态下所做的更改)?

C
Community

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

如果要删除与分离的 HEAD 关联的更改

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

git checkout master

下次你更改了一个文件并想将它恢复到它在索引中的状态时,不要先删除文件,只需执行

git checkout -- path/to/foo

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

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

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


“这会将文件 foo 恢复到您对其进行任何更改之前的状态。” --> 它将恢复到它在索引中的状态 - 请编辑
为什么首先会发生此错误?这是我讨厌 git 的原因之一——有时是完全随机的行为。 Mercurial从来没有遇到过这样的问题。
@VioletGiraffe 这既不是错误也不是随机的——它只是您的存储库在签出先前提交时进入的状态。 “分离的头”用作警告,如果您打算从该点开始做任何工作,您可能还想创建或指向一个分支。但是,如果您只是想查看该标记或提交,那么处于分离的头部状态并没有错。
如果您已承诺分离头,请不要这样做,请参阅其他答案。如果是这样,您可以查看之前在 Previous HEAD position was 7426948... 中提到的 head git
@VioletGiraffe:你有一个基于 Mercurial 的心智模型,但你使用的是 Git。如果你不愿意调整你的心智模型以适应 Git 的模型,那么事情将继续显得随机。这就像你戴着 VR 护目镜在外面走来走去,你以为你在开飞机,但实际上你是在过马路。你会被汽车撞到的。
C
Community

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

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

摘自:

What to do with commit made in a detached head


我发现这是首选的解决方案 - 特别是如果您想保留在签出单个版本时所做的更改。
@adswebwork:我同意。所有其他答案都建议恢复到以前的状态并丢失在分离的头部状态下本地进行的更改。
为什么不 git stash ?因为这是我想到的第一件事。创建一个新的分支将是一个矫枉过正。
您也可以 git rebase my-temporary-work 然后删除分支 git branch -d my-temporary-work,这样看起来就好像您首先提交到了正确的分支。
@geekay git stash 听起来确实是这个案例的完美工具。您能否用建议的步骤写一个答案来实现这一目标?
t
tanius

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

当您已经在此模式下更改了某些内容并且(可选)想要保存更改时,如何退出(“修复”)分离的 HEAD 状态:

提交您想要保留的更改。如果您想接管您在分离 HEAD 状态下所做的任何更改,请提交它们。像: git commit -a -m "your commit message" 放弃你不想保留的更改。硬重置将丢弃您在分离的 HEAD 状态下所做的任何未提交的更改: git reset --hard (没有这个,第 3 步将失败,抱怨在分离的 HEAD 中修改了未提交的文件。)检查您的分支。通过检查您之前工作的分支退出分离的 HEAD 状态,例如: git checkout master 接管您的提交。您现在可以通过挑选来接管您在分离 HEAD 状态下所做的提交,如我对另一个问题的回答所示。 git reflog git cherry-pick ...


git reset --hard 正是我需要的,因为我希望上游成为源并且应该删除本地更改。
我几乎对这个解决方案投了反对票,直到我看到第 4 步。多么恐慌(我一直跟着到第 3 步,然后......)。感谢您的解决方案。
P
Peter Mortensen

分离头的意思:

您不再在分支上,您已在历史记录中签出单个提交

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

  git checkout master

如果您有想要保留的更改:

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

git branch  temp
git checkout master
git merge temp

完美,然后在删除分支温度后
要从一个分支切换到另一个分支,git 现在接受动词开关:git-scm.com/docs/git-switch。除了您可能更喜欢哪个动词之外,checkout 的缺点是它被用于各种其他目的git-scm.com/docs/git-checkout
M
MarianD

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

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

https://i.stack.imgur.com/6mrfN.jpg

换句话说:

如果它直接指向提交,则 HEAD 被分离。

如果它间接指向一个提交(即它指向一个分支,该分支又指向一个提交),则附加 HEAD。

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

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

https://i.stack.imgur.com/a9uTf.jpg

现在我们要执行 git checkout — 在各个图片中使用不同的目标(它们顶部的命令变暗以强调我们只是打算应用这些命令):

https://i.stack.imgur.com/Ph7Y5.jpg

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

https://i.stack.imgur.com/ZgKkM.jpg

如您所见,HEAD 指向 git checkout 命令的 target — 指向一个 branch(四联体的前 3 个图像),或(直接)指向一个commit(四胞胎的最后一张图片)。

工作目录的内容也被更改,以符合适当的提交(快照),即与 HEAD (直接或间接)指向的提交一致。

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

https://i.stack.imgur.com/6mrfN.jpg


缺少的是:“当我签出一个也是某个分支顶部的数字提交时,它会导致头部分离,还是会使用关联的分支?”我的猜测是:“那就没有分离的头”
@U.Windl,回答你自己——然后 HEAD 会指向一个分支(这反过来又会指向一个提交),还是 HEAD 会直接指向一个提交?在您回答之后,请参阅我的回答开头。
我知道可以直接签出修订版,而无需签出恰好指向它的分支。逻辑上:两个或多个分支可以指向同一个版本。如果您然后通过其哈希检查修订,该命令将选择哪个分支?
@Mike,不会选择任何分支,所有分支(作为提交的指针)将保持不变 - 您可以在我的答案的所有图片(棕色框)中看到它。只有 HEAD 不会指向分支,而是直接指向提交,因此您将以“Detached HEAD”状态结束 - 请参见最后一张(右下角)图片。 - 尽管有 2 个分支指向同一个提交,但如果您通过哈希选择此提交,HEAD 将不会指向这 2 个分支之一,而是直接指向该提交。
@MarianD 我认为有一点误解——我在解释为什么当你通过哈希选择一个修订版时,你不能指望 Git 签出一个分支。
m
mojuba

如果您进行了更改,然后意识到您处于超然状态,您可以执行以下操作:stash -> checkout master -> stash pop:

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

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


已为这个坏男孩添加了书签 - 节省了制作临时分支的时间。工作了一个款待。
在签出 git 子模块后,我经常会进入分离的 HEAD 状态,然后对其进行更改。我发现这是修复问题的最佳和最简单的解决方案,因此我可以保留我的更改。
如果您已经在分离状态下提交了更改,这不起作用?
P
Philippe Gerber

这是我在意识到自己处于超然状态并且已经做出一些改变之后所做的事情。

我提交了更改。

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

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

$ git checkout master
Switched to branch 'master'

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

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

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


这应该是答案。它会取回您的 nuked 文件。
是的,这确实是最简单的事情 - 足够简单,下次发生时无需搜索网络即可记住。提交,记下哈希,返回您要提交的分支,然后 git cherry-pick <hash>
感谢您的解决方案。这有帮助。我还可以补充一点,我必须执行“git push origin master”,以便我的 master 和 origin/master 指向同一个提交。
这实际上是 tanius' answer(一年多前发布)。
感谢这个愉快的选择恢复了最后的分离头变化
l
larsks

当您在 git 中签出特定提交时,您最终会处于 分离头 状态...也就是说,您的工作副本不再反映命名引用的状态(如“master” )。这对于检查存储库的过去状态很有用,但如果您实际上尝试还原更改,则不是您想要的。

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

git checkout myfile

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

git reset --hard HEAD^

但是,如果您与其他人共享存储库,则 git reset 可能会造成干扰(因为它会删除存储库历史的一部分)。如果您已经与其他人共享了更改,您通常希望查看 git revert,它会生成一个“反提交”——也就是说,它会创建一个新的提交来“撤消”相关更改。

The Git Book 有更多详细信息。


正如我在@ralphtheninja 的回答中所说,git checkout path/to/foo 可能与 git checkout some-branch 冲突,因此最好使用 git checkout -- path/to/foo 来避免这些冲突。
y
yyny

由于“分离头状态”使您处于临时分支上,因此只需使用 git checkout - 即可将您置于您所在的最后一个分支上。


小心,当你处于分离的头部状态时,你会丢失你所做的任何提交。
@Ajak6 你并没有真正失去那些提交。它们仍然可以通过 git reflog 使用,并且可以被接管到新分支或通过 git cherry-pick 进入现有分支。请参阅this question
但是,在一段时间后,任何没有被分支或标签(或不是当前工作修订)或不是此类修订的祖先的修订都可能被永久删除.
J
Johnny Cage

您可能做过git reset --hard origin/your-branch

尝试仅git checkout your-branch


P
Pat. ANDRIA

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

您可以选择仅通过以下方式创建与您的提交相关联的新分支

git branch new-branch-name

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

或者如果你想回到之前的状态,你需要选择之前被选中的分支

git checkout @{-1}


T
Timo

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

https://i.stack.imgur.com/Q1HKx.png

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


D
David Brower

附录

如果您希望返回的分支是您最后一次结帐,您可以简单地使用 checkout @{-1}。这将带您回到之前的结帐。

此外,您可以使用例如 git global --config alias.prev 为该命令设置别名,这样您只需键入 git prev 即可切换回之前的结帐。


我需要的是在我重新定位我的分支之前找回我的 HEAD 的方法。这解决了我的问题!非常感谢:)
L
Leniel Maccaferri

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

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

之后...使用以下命令检查您想要的分支:

假设您想要分支 MyOriginalBranch:

git checkout -b someName origin/MyOriginalBranch


a
alexhg

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

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

手动备份存储库,以防出现意外错误。提交您想保留的最后更改。创建一个临时分支(我们将其命名为 detached-head),它将包含处于当前状态的文件:

git checkout -b detached-head

(a) 如果不需要保留 master 分支,请删除它

git branch -D master

(b) 或者如果您想保留它,请重命名

git branch -M master old-master

将临时分支重命名为新的主分支

git branch -M detached-head master

图片来源:改编自 Gary Lai 的this Medium article


S
Souhaib

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

请在切换分支之前提交您的更改或存储它们。中止

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

git checkout -f master

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


S
Sterling Diaz

Git告诉我怎么做。

如果您输入:

git checkout <some-commit_number>

保存状态

git add .
git commit -m "some message"

然后:

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

K
Krishnadas PC

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

git checkout other_branch // 当您需要该提交哈希中的代码创建一个新分支并将提交哈希指向新创建的分支时,这是不可能的。

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


这就是为什么我有这个错误。我签出了一个修订版,然后再次签出到当前/最新的修订版,而不是签出到分支,这将正确地附加头部。谢谢您的帮助。
J
JonnyRaa

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

它不会让我推动,因为我不被认为在我认为我所在的分支上。

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

解决方案只是执行以下操作:

git branch -f myStuckBranch HEAD
git checkout myStuckBranch

即使 HEAD 和 myStuckBranch 现在指向同一事物,您也需要进行结帐,因为您仍然被认为处于分离的头部状态(而不是在分支上)

我不是 git 专家(主要使用 mercurial,它永远不会造成这种奇怪的情况),但我对这个命令的理解是它只是说“将 myStuckBranch 更改为指向 HEAD”。

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

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

不得不一直手动执行此操作有点烦人,但仍然比更改工作目录只是为了更新另一个分支以合并其中的更改要好。


你的第一组命令正是我所处的场景。我也来自 Mercurial,令人惊讶的是,与分离的容易程度相比,重新连接一个人的头是多么困难。对于您的第二组命令,您应该只在本地签出 master - git pull 已经为您执行了 git fetchgit merge。毫无意义地让事情变得更复杂是没有意义的(尽管了解正在发生的事情总是很好的)!
是的,我现在正要习惯 git,但我仍然觉得这有点古怪。顺便说一句,您可以将第一个命令与 git checkout -B myStuckBranch
对于第二个,目的是根本不交换分支,而只是将 master 合并到当前分支中。如果您签出 master ,那么您必须拉出然后再次签出您的原始分支以进行合并。我倾向于有一个监视文件更改打开的构建,因此当我实际上没有做任何事情时避免搅动工作目录
使用第二组命令,您可以在检出辅助分支时执行以下操作:git pull origin master。这不会更新您的本地存储库的 master 分支,但它会获取然后将 origin/master 合并到当前分支中。您也可以执行 git fetch; git merge origin/master(它不会更新您的本地 master 分支)。甚至是 git fetch origin master:master; git merge master(它会像您的代码段一样更新您的本地 master 分支,但需要更多输入)。再说一次,做你理解的事情更重要!
P
Paul Rooney

我想保留我的更改,所以我只是解决这个问题......

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

那对我有用


D
DZet

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

git add .

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

git commit -a -m "my adjustment message"

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

git checkout -b new_branch_name

您将拥有一个新分支,并且您的所有调整都将在该新分支中进行。然后,您可以根据需要继续推送到远程和/或结帐/拉取/合并。


U
U. Windl

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

(假设所有内容都已提交(工作树是“干净的”))保存我的提交消息: git log > /tmp/log 保存我的工作树: mkdir /tmp/backup && cp -a all_my files_and_directories /tmp/backup 恢复为主: git checkout master 删除所有工作文件和目录:rm ... 使用备份:cp -a /tmp/backup/。 . git add 和 git commit 使用保存的 /tmp/log 中的消息,也许用不同的文件子集重复它......

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


g
gebbissimo

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

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

之后,您可能希望将此新分支与其他分支合并。总是有用的是 git "a dog" 命令:

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

A
Amjedonline
git pull origin master

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


l
lenooh

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

git checkout new_branch_name detached_head_garbage_name


E
Edgar Alejandro Ramirez

使用 git rebase 您可以将 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 commit --amend 命令而创建的。

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

git rebase bfcb8f9

这将使您的分支的 HEAD 指向所需的提交(在这种情况下是最新的):

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