题 如何将分离的HEAD与master / origin协调?


我是Git分支复杂的新手。我总是在一个分支上工作并提交更改,然后定期推送到我的远程源。

在最近的某个地方,我做了一些文件的重置,让他们退出提交阶段,后来做了一个 rebase -i 摆脱最近的几个本地提交。现在我处于一种我不太了解的状态。

在我的工作区域, git log 显示了我所期待的 - 我在正确的火车上有我不想要的提交,还有新的提交等等。

但是我只是推送到远程存储库,并且有什么不同 - 我在rebase中杀死的一些提交被推送,而本地提交的新提交不存在。

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


1275
2018-04-24 17:51


起源


你有没有推动改变之前的提交? - manojlds
@manojlds:不确定你的意思。我推迟了一段时间,但不是之前。 - Ben Zotto
就像你之前推送你在rebase -i中删除的提交一样。从你的回答我想不到。 - manojlds
@manojlds:正确。我只杀了比最近的推送更新的提交。 (虽然如我所说,我已经推了,因为我觉得一切都好) - Ben Zotto
你能解释一下你做了什么 I did a reset of some files to get them out of commit staging 部分?对不起,问题:) - manojlds


答案:


首先,让我们澄清一下 什么是HEAD 分离时意味着什么。

HEAD是当前签出的提交的符号名称。当HEAD未脱离时(“正常”)1 情况:你有一个分支检出),HEAD实际指向分支的“ref”,分支指向提交。因此HEAD“附着”到分支。进行新提交时,HEAD指向的分支将更新为指向新提交。 HEAD会自动跟随,因为它只指向分支。

  • git symbolic-ref HEAD 产量 refs/heads/master
    名为“master”的分支已签出。
  • git rev-parse refs/heads/master 产量 17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或“头”。
  • git rev-parse HEAD 也是收益率 17a02998078923f2d62811326d130de991d1a95a
    这就是“象征性的参考”意味着什么。它通过其他参考指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来更改为具有额外解释的普通文件,以便它们可以在没有符号链接的平台上使用。)

我们有 HEAD → refs/heads/master → 17a02998078923f2d62811326d130de991d1a95a

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

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

我们有 HEAD → 17a02998078923f2d62811326d130de991d1a95a

使用分离的HEAD要记住的重要一点是,如果它指向的提交是未引用的(没有其他引用可以到达它),那么当你签出其他提交时它将变成“悬空”。最终,这样的悬挂提交将通过垃圾收集过程进行修剪(默认情况下,它们至少保存2周,并且可以通过HEAD的reflog引用来保持更长时间)。

1 使用独立的HEAD进行“正常”工作是完全正常的,你只需要跟踪你正在做的事情,以避免不得不从reflog中删除历史记录。


交互式rebase的中间步骤是使用分离的HEAD完成的(部分是为了避免污染活动分支的reflog)。如果完成完整的rebase操作,它将使用rebase操作的累积结果更新原始分支,并将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 如果远程分支无法“快速转发”到新提交(即你丢弃,或重写一些现有的提交,或以其他方式重写了一些历史记录),则推送到此命令的末尾。

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


2166
2018-04-24 19:56



真棒。这样的东西表明git有改进的余地。有时候在项目工作的中间,根本就没有浪费时间的空间,而这简直令人讨厌。但除此之外,git真的很棒。 - BastiBen
复杂的版本控制系统变得如此令人难以置信 - Antonio Sesto
为什么在Gll这么该死的复杂... omg,我想做的就是创建一个新的分支在那里做一些改变并推动它,然后切换回master并继续工作,但随后它一直在抱怨脱落的头废话。你的回答保存了我留在头皮上的几根头发。 - Space monkey
这是一个很好的答案,但我认为不需要临时分支(虽然我通常使用自己的一个)。 git branch -f master HEAD && git checkout master 就足够了 - 假设你的目标是保持目前的头脑,但将其指定为 master。其他目标也有意义,并呼吁其他食谱。 - Adrian Ratnapala
大声笑着关于长度的评论。然而,我们其他人只是扫描直到我们到达“从你的情况中恢复[...]”的路线,并从那里开始 - 同时做一个心理记录,有一个有用的,很好解释的背景故事,我们可以阅读在一个下雨天。该 选项 阅读更多不会伤害你,但它 不 有利于他人。 - underscore_d


这样做:

git checkout master

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

git checkout -b temp
git checkout -B master temp

514
2017-09-18 07:23



谢谢你的简洁。不是每个人都有时间参加“首先,让我们澄清一下HEAD是什么......”的答案。 - Brian Risk
这是一个危险的回应。到达这个答案的人有不同的状态,“只是做这个来解决它”回答不回答问题。这个很容易破坏工作。 - Archonic
!“git checkout master”如果分离的头部不是主人的一部分,将导致所有更改丢失! - Tony
@Blauhirn您可能已经签出了提交,而不是分支。分支仍指向相同的提交,但您处于不同的“模式”。 - Daniel Alexiuc
这非常有效!更容易解决上面接受的答案! - Tfish


我遇到了这个问题,当我读到最高投票答案:

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

我想:啊哈!如果 HEAD 是当前结帐提交的符号名称,我可以将其与之协调 master 通过对它进行反驳 master

git rebase HEAD master

这个命令:

  1. 退房 master
  2. 标识的父提交 HEAD 回到原点 HEAD 分道扬.. master
  3. 播放那些提交 master

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


关于遥控器:

我在rebase中杀死的几个提交被推了出来,而那些在本地提交的新提交不在那里。

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

推后 master 远程 origin,您的远程跟踪分支 origin/master 将更新为指向相同的提交 master


97
2017-08-02 03:10



git:“首先,重新开始重温你的工作......快速转发大师到HEAD。”我:“太棒了!” - Benjamin
谢谢,扫描了一个不是多页阅读的答案 - Ally


在这里查看分离头的基本解释:

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

用于可视化它的命令行:

git branch

要么

git branch -a

你会得到如下输出:

* (no branch)
master
branch1

* (no branch) 显示你处于分离的头脑中。

你可以通过做一个来到这个州 git checkout somecommit 它会用以下方法警告你:

你处于'独立的HEAD'状态。您   可以环顾四周,做实验   改变并提交它们,你可以   放弃你在此提交的任何提交   国家不影响任何分支机构   通过执行另一个结帐。

如果要创建新分支   保留您创建的提交,您可以这样做   所以(现在或以后)使用-b和   再次结帐命令。例:

git checkout -b new_branch_name

现在,让他们成为主人:

做一个 git reflog 甚至只是 git log 并记下你的提交。现在 git checkout master 和 git merge 提交。

git merge HEAD@{1}

编辑:

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


78
2018-04-24 18:41



感谢这里的细节和信息指示。似乎没有必要进行显式合并,但这可以看出我将回到的一些概念。谢谢。 - Ben Zotto
“@ {1}”有什么作用? - ebi


将您的分离提交放到自己的分支上

简单地跑 git checkout -b mynewbranch

然后跑 git log,你会看到提交现在 HEAD 在这个新的分支上。


29
2018-05-20 02:44



如果我这样做,那样做 mynewbranch 附加什么? - Benjohn
是的,它附着在分离的头部附着的地方,这正是我想要的。谢谢! - Benjohn


如果你只是主分支并想回到“开发”或功能只是这样做:

git checkout origin/develop

注意:退房 原产地/开发

你在 分离头 州。你可以环顾四周,做实验 更改并提交它们,您可以放弃您在此中提交的任何提交 通过执行另一次结账而不影响任何分支的状态...

然后

git checkout -b develop

有用 :)


18
2017-11-08 13:24



对我有用的不是'git checkout origin / develop',而是'git checkout develop'。使用'origin / develop'总是没有变化,因此留在“HEAD脱离原点/开发”。跳过“原点”部分修复了一切。 - DrStrangepork


如果你想推动你当前的分离式HEAD(检查 git log 之前),尝试:

git push origin HEAD:master

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


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

git rebase HEAD master
git checkout master

看到: Git:“目前没有任何分支机构。”在保持变化的同时,是否有一种简单的方法可以回到分支机构?


16
2017-09-17 20:35



这确实将分离的提交发送给origin / master。要将头部连接到本地分支,请执行以下操作: stackoverflow.com/a/17667057/776345 - Paschalis
当我这样做时,我得到了这个存储库是为Git LFS配置的,但在你的路径上找不到'git-lfs'。如果您不再希望使用Git LFS,请删除.git / hooks / post-checkout以删除此挂钩。 - user2568374


如果你完全确定HEAD是好状态:

git branch -f master HEAD
git checkout master

你可能无法推动原点,因为你的主人已经偏离了原点。如果您确定没有其他人使用回购,您可以强制推送:

git push -f

如果您在功能分支上没有其他人使用,则最有用。


7
2018-03-01 09:31



正确的回答就在那里 - octohedron


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

git push origin HEAD:master
git checkout master        
git pull

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

第二个移动到分支主人。

第三个恢复连接到分支主机的HEAD。

如果推送被拒绝,第一个命令可能会出现问题。但这不再是分离头的问题,而是关于分离的HEAD不知道某些远程变化的事实。


7
2018-01-07 12:13



没有用,我得到了:这个存储库是为Git LFS配置的,但在你的路径上找不到'git-lfs'。如果您不再希望使用Git LFS,请通过删除.git / hooks / pre-push来删除此挂钩。你目前不在分公司。请指定要合并的分支。 - user2568374


您所要做的就是'git checkout [branch-name]',其中[branch-name]是您进入分离头状态的原始分支的名称。 (从asdfasdf分离)将消失。

因此,例如,在分支'dev'中,您可以检出提交asdfasd14314 - >

'git checkout asdfasd14314'

你现在处于一个独立的头状态

'git branch'将列出类似 - >的内容

* (detached from asdfasdf)
  dev
  prod
  stage

但要摆脱独立的头状态并回到开发 - >

'git checkout dev'

然后'git branch'将列出 - >

* dev
  prod
  stage

但是,当然如果你不打算保持对独立头部状态的任何改变,但是我发现自己这样做了很多,不打算做任何改变而只是为了查看先前的提交


4
2017-10-17 19:49