如何使分离的 HEAD 与主站 / 源站协调?

我对 Git 的分支复杂性并不陌生。我总是在单个分支上工作并提交更改,然后定期推送到我的远程源。

最近,在某个地方,我对一些文件进行了重置,以使它们脱离提交暂存,然后进行了rebase -i以摆脱一些最近的本地提交。现在我处于一种不太了解的状态。

在我的工作区中, git log准确地显示了我的期望 - 我在正确的火车上带着不想走的提交,那里有新的提交,等等。

但是我只是推送到远程存储库,而又有什么不同–我在 rebase 中杀死的几个提交被推送了,而本地提交的新提交则不存在。

我认为 “master / origin” 是与 HEAD 分离的,但是我不清楚这是什么意思,如何使用命令行工具对其进行可视化以及如何对其进行修复。

答案

首先,让我们弄清HEAD 是什么,分离后的含义。

HEAD 是当前已检出提交的符号名称。如果未分离 HEAD(“正常” 1情况:您已签出分支),则 HEAD 实际上指向分支的 “ref”,而分支则指向提交。 HEAD 因此 “附加” 到分支。当您进行新的提交时,HEAD 指向的分支将更新为指向新的提交。 HEAD 自动跟随,因为它仅指向分支。

  • git symbolic-ref HEAD产生refs/heads/master
    名为 “master” 的分支已签出。
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a
    该提交是 master 分支的当前提示或 “头部”。
  • git rev-parse HEAD也产生17a02998078923f2d62811326d130de991d1a95a
    这就是成为 “符号引用” 的含义。它通过其他一些引用指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来更改为带有额外解释的纯文件,以便可以在没有符号链接的平台上使用。)

我们有HEADrefs/heads/master 17a02998078923f2d62811326d130de991d1a95a refs/heads/master17a02998078923f2d62811326d130de991d1a95a

分离 HEAD 时,它直接指向一个提交,而不是通过分支间接指向一个提交。您可以将分离的 HEAD 视为未命名的分支。

  • git symbolic-ref HEAD失败并出现fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD产生17a02998078923f2d62811326d130de991d1a95a
    由于它不是符号引用,因此必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

对于分离的 HEAD 要记住的重要一点是,如果指向它的提交未被引用(其他引用无法到达它),那么当您签出其他提交时,它将变成 “悬挂”。最终,此类悬空的提交将在垃圾回收过程中被修剪(默认情况下,它们至少保留 2 周,并且可能被 HEAD 的 reflog 引用保留更长时间)。

1使用分离的 HEAD 进行 “正常” 工作是完全可以的,您只需要跟踪自己在做什么就可以避免从 reflog 中删除掉历史记录。


交互式基础的中间步骤是通过分离的 HEAD 完成的(部分是为了避免污染活动分支的引用日志)。如果您完成了完整的变基操作,它将使用变基操作的累积结果更新原始分支,并将 HEAD 重新附加到原始分支。我的猜测是您永远不会完全完成变基过程。这将使您留下一个分离的 HEAD,指向由 rebase 操作最近处理的提交。

为了从您的情况中恢复过来,您应该创建一个分支,该分支指向分离的 HEAD 当前指向的提交:

git branch temp
git checkout temp

(这两个命令可以缩写为git checkout -b temp

这会将您的 HEAD 重新连接到新的temp分支。

接下来,您应该将当前提交(及其历史记录)与预期在其上进行操作的普通分支进行比较:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(您可能要尝试使用日志选项:添加-p ,取消--pretty=…以查看整个日志消息,等等。)

如果您的新temp分支看起来不错,则您可能需要更新(例如) master指向它:

git branch -f master temp
git checkout master

(这两个命令可以缩写为git checkout -B master temp

然后,您可以删除临时分支:

git branch -d temp

最后,您可能需要推送重新建立的历史记录:

git push origin master

如果无法将远程分支 “快速转发” 到新提交,则可能需要在此命令的末尾添加--force以进行推送(即,您删除或重写了一些现有的提交,或者以其他方式重写了一些历史记录) )。

如果您正在执行变基操作,则可能应该清理它。您可以通过查找目录.git/rebase-merge/来检查是否正在进行.git/rebase-merge/ 。您只需删除该目录即可手动清理进行中的基准库(例如,如果您不再记得活动的基准库操作的目的和上下文)。通常,您将使用git rebase --abort ,但是这样做可能会避免一些额外的重置操作(它将 HEAD 移回原始分支,并将其重置为原始提交,这将撤消我们上面所做的一些工作)。

只要这样做:

git checkout master

或者,如果您要保留更改,请执行以下操作:

git checkout -b temp
git checkout -B master temp

我遇到了这个问题,当我在投票结果中投票时:

HEAD 是当前已检出提交的符号名称。

我以为:啊哈!如果HEAD是为 currenlty 符号名结账承诺,我可以调和这对master通过衍合靠在master

git rebase HEAD master

该命令:

  1. 签出master
  2. HEAD的父提交标识回HEADmaster发散点
  3. master上播放这些提交

最终结果是所有在HEAD但不在master中的提交也都在mastermaster仍然签出。


关于遥控器:

我在 rebase 中杀死的一些提交被推送了,而本地提交的新提交不存在。

远程历史记录无法再使用您的本地历史记录进行快速转发。您需要强制按下( git push -f )以覆盖远程历史记录。如果您有任何合作者,通常需要与他们进行协调,以便所有人都在同一页面上。

master推送到远程origin ,远程跟踪分支的origin/master将更新为指向与master相同的提交。

在这里查看分离头的基本说明:

http://git-scm.com/docs/git-checkout

命令行将其可视化:

git branch

要么

git branch -a

您将得到如下输出:

* (no branch)
master
branch1

* (no branch)表示您处于分离状态。

您可能已经通过执行git checkout somecommit等进入这种状态,并且它会通过以下警告您:

您处于 “分离头” 状态。您可以环顾四周,进行实验性更改并将其提交,也可以放弃在此状态下所做的任何提交,而不会通过执行另一次签帐而影响任何分支。

如果要创建新分支以保留创建的提交,则可以(现在或以后)通过再次将 - b 与 checkout 命令一起使用来进行。例:

git checkout -b new_branch_name

现在,让他们成为主人:

做一个git reflog甚至只是git log并记录您的提交。现在git checkout mastergit merge提交。

git merge HEAD@{1}

编辑:

要添加,请使用git rebase -i不仅用于删除 / 杀死不需要的提交,还用于编辑它们。只需在提交列表中提及 “编辑”,您就可以修改提交,然后发出git rebase --continue继续进行。这样可以确保您永远不会进入一个独立的 HEAD。

将分离的提交放入自己的分支

只需运行git checkout -b mynewbranch

然后运行git log ,您将看到此新分支上的提交现在为HEAD

如果您只有 master 分支并想返回 “开发” 或功能,请执行以下操作:

git checkout origin/develop

注意:签出origin / develop

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

然后

git checkout -b develop

有用 :)

如果要推送当前分离的 HEAD(请先检查git log ),请尝试:

git push origin HEAD:master

将您的分离的 HEAD 从原点发送到 master 分支。如果您的推送被拒绝,请首先尝试使用git pull origin master来获取来自 origin 的更改。如果您不关心原点的更改而被拒绝,因为您做了一些有意的变基,并且想用当前分离的分支替换 origin / master - 那么您可以强制执行( -f )。如果您失去了对先前提交的访问权限,则始终可以运行git reflog来查看所有分支的历史记录。


要返回主分支,同时保留更改,请尝试以下命令:

git rebase HEAD master
git checkout master

请参阅: Git:“当前不在任何分支上”。有没有一种简单的方法可以在保留更改的情况下返回分支?

我今天刚遇到这个问题,很确定我可以通过以下方法解决它:

git branch temp
git checkout master
git merge temp

当我弄清楚如何做到这一点时,我正在工作计算机上,现在我的个人计算机上也遇到了同样的问题。因此,当我回到工作计算机时,必须等到星期一,才能确切地了解我的工作方式。

我在搜索You are in 'detached HEAD' state.时发现了这个问题You are in 'detached HEAD' state.

与过去相比,我分析了到达这里所做的事情后,发现自己犯了一个错误。

我的正常流程是:

git checkout master
git fetch
git checkout my-cool-branch
git pull

这次我做了:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.

问题是我不小心做了:

git checkout origin/my-cool-branch

而不是:

git checkout my-cool-branch

解决方法(在我的情况下)只是运行上面的命令,然后继续执行流程:

git checkout my-cool-branch
git pull

以下对我有用(仅使用分支主机):

git push origin HEAD:master
git checkout master        
git pull

第一个将分离的 HEAD 推到远程原点。

第二个移动到分支主机。

第三个恢复与分支主机关联的 HEAD。

如果拒绝推送,则在第一个命令上可能会出现问题。但是,这不再是分离的 Head 的问题,而是关于分离的 HEAD 不了解某些远程更改的事实。