我怎样才能调和分离的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
    名为“主”的分支被检出。
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或“头”。
  • git rev-parse HEAD也产生17a02998078923f2d62811326d130de991d1a95a
    这就是“符号参考”。 它通过一些其他的参考指向一个对象。
    (符号参考最初是以符号链接的forms实现的,但后来更改为带有额外解释的普通文件,以便可以在没有符号链接的平台上使用它们。)

我们有HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

当HEAD被分离时,它直接指向一个提交 – 而不是通过一个分支间接地指向一个提交。 你可以把分离的HEAD想象成一个未命名的分支。

  • git symbolic-ref HEAD失败fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD得出17a02998078923f2d62811326d130de991d1a95a
    由于它不是一个符号参考,它必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

用分离的HEAD来记住的重要的事情是,如果它指向的提交不被引用(其他引用无法达到它),那么当你签出其他提交时,它将变成“悬挂”。 最终,这种悬而未决的提交将通过垃圾收集过程被修剪(默认情况下,它们被保留至less2周,并且可以通过被HEAD的reflog引用而保持更长的时间)。

1用一个独立的HEAD进行“正常”的工作是完全正确的,你只需要跟踪你正在做的事情,以避免把丢失的历史logging排除在reflog之外。


交互式重新分配的中间步骤是用分离的HEAD完成的(部分是为了避免污染活动分支的reflog)。 如果您完成了全部的rebase操作,它将更新您的原始分支与rebase操作的累积结果,并将HEAD重新附加到原始分支。 我的猜测是,你从来没有完全完成rebase进程; 这会让你有一个分离的HEAD指向最近由rebase操作处理的提交。

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

 git branch temp git checkout temp 

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

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

接下来,您应该将当前提交(及其历史logging)与您希望在其中工作的常规分支进行比较:

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

(你可能想要试验一下日志选项:add -p ,leave off --pretty=…来查看整个日志信息等)

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

 git branch -f master temp git checkout master 

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

您可以删除临时分支:

 git branch -d temp 

最后,你可能会想推动重build的历史:

 git push origin master 

如果远程分支不能被快速转发到新的提交中,你可能需要在这个命令的最后添加--force (即,你删除了,或者重写了一些现有的提交,或者重写了一些历史logging)。

如果您正在进行重新布局操作,您应该清理它。 您可以通过查找目录.git/rebase-merge/来检查是否正在进行重新.git/rebase-merge/ 。 您可以通过删除该目录(例如,如果您不再记住活动的rebase操作的目的和上下文)来手动清理正在进行的rebase。 通常你会使用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的父提交标识回到从master发出的头HEAD
  3. master之上播放这些提交

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


关于偏远:

我在基地被杀的几个提交被推了,在当地犯下的新提交不在那里。

远程历史logging不能再使用本地历史logging进行快速转发。 你需要强制推( 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等来达到这个状态,它会提醒你以下几点:

你处于“脱离头”状态。 您可以环顾四周,进行实验性更改并提交它们,并且可以放弃您在此状态下进行的任何提交,而不会通过执行另一个结算来影响任何分支。

如果您想要创build一个新的分支来保留您创build的提交,可以通过再次使用-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 – 继续前进。 这将确保你从来没有进入一个独立的头。

让你的分离提交到自己的分支

只需运行git checkout -b mynewbranch

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

如果你只是掌握了分支,想回到“开发”或者一个function,只需要这样做:

 git checkout origin/develop 

注意:检查出处/发展

您处于分离的HEAD状态。 你可以环顾四周,做实验性的修改并提交它们,你可以放弃你在这个状态下进行的任何提交,而不会影响任何分支机构,通过执行另一个结帐…

然后

 git checkout -b develop 

有用 :)

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

 git push origin HEAD:master 

将你分离的HEAD发送到原始分支。 如果您的推送被拒绝,请先尝试git pull origin master以从原点获取更改。 如果你不关心来自原产地的变化,它被拒绝了,因为你做了一些有意的变更,而你想用当前分离的分支replaceorigin / master,那么你可以强制它( -f )。 如果你失去了一些访问以前的提交,你总是可以运行git reflog查看所有分支的历史。


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

 git rebase HEAD master git checkout master 

请参阅: Git:“目前没有任何分支”。 有没有一种简单的方法来恢复分支,同时保持更改?

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

 git branch -f master HEAD git checkout master 

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

 git push -f 

如果您在function分支上没有其他人正在使用,那么这将非常有用。

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

所以例如,在分支'dev'中签出提交asdfasd14314 – >

 'git checkout asdfasd14314' 

你现在处于独立的头部状态

“git分支”将列出类似于 – >的内容

 * (detached from asdfasdf) dev prod stage 

但要离开头部状态并回到开发 – >

 'git checkout dev' 

然后'git分支'将列出 – >

 * dev prod stage 

但是这当然是,如果你不打算保持从分离头部状态的任何变化,但我发现自己做了很多不打算做任何改变,只是看看以前的提交

我今天刚刚遇到这个问题。 很确定我通过这样做来解决它:

 git branch temp git checkout master git merge temp 

当我想到如何做到这一点的时候,我正在我的工作电脑上,现在我正在遇到同样的问题。 所以当我回到工作岗位时,必须等到星期一才看到我是如何做到的。

而不是做git checkout origin/master

只要做git checkout master

那么git branch会确认你的分支。

对我来说,就像删除本地分支一样简单,因为我没有任何我想要推动的本地提交:

所以我做了:git branch -d branchname

然后再检查分支

git checkout branchname

简单的说,Detached HEAD状态意味着你没有签出任何分支的头(或者提示)

以例子来理解

大多数情况下的分支是多个提交的序列,如:

提交1: master – > branch_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

提交2: master – > 123be6a76168aca712aea16076e971c23835f8ca – > branch_HEAD(100644a76168aca712aea16076e971c23835f8ca)

正如你可以在上面看到的情况下提交你的分支指向你最近的提交。 所以在这种情况下,如果你签出提交123be6a76168aca712aea16076e971c23835f8ca那么你将处于分离头状态,因为你的分支的HEAD指向100644a76168aca712aea16076e971c23835f8ca,并且在技术上你在没有分支的HEAD处检出。因此,你处于分离的HEAD状态

理论解释

在这个博客中,明确指出的Git仓库是一个提交树,每个提交指向它的祖先,每个提交指针被更新,并且这些指向每个分支的指针被存储在.git / refs子目录中。 标签存储在.git / refs /标签中,分支存储在.git / refs /头中。 如果您查看任何文件,您会发现每个标记对应于一个文件,具有40个字符的提交哈希值,正如上面@Chris Johnsen和@Yaroslav Nikitenko所解释的那样,您可以查看这些参考文献

如果你在master的顶部做了一些提交并且只想在那里“向后合并” master (即你想让master指向HEAD ),那么单行就是:

 git checkout -B master HEAD 
  1. 这创build了一个名为master的新分支,即使它已经存在(这就像移动master ,这就是我们想要的)。
  2. 新创build的分支被设置为指向HEAD ,这是你的位置。
  3. 新的分支被检出,所以你在之后的master

我发现这在子存储库的情况下特别有用,而这些子存储库也经常处于分离状态。

我进入了一个非常愚蠢的状态,我怀疑其他人会发现这个有用的….但以防万一

 git ls-remote origin 0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b HEAD 6f96ad0f97ee832ee16007d865aac9af847c1ef6 refs/heads/HEAD 0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b refs/heads/master 

我最终解决了这个问题

 git push origin :HEAD 

在我的情况下,我运行git status ,我看到我的工作目录上有几个未跟踪的文件。

为了使重build工作,我只需要清理它们(因为我不需要它们)。

如果你在eclipse中使用egit:假设你的主人是你的主要开发分支

  • 将更改提交给通常是新的分支
  • 然后从遥控器拉
  • 然后右键单击项目节点,select团队,然后select显示历史logging
  • 然后右键点击主,select退房
  • 如果日食告诉你,有两个主人一个本地一个远程,select远程

在此之后,您应该能够重新连接到原始主人

这完美地为我工作:

1. git stash保存您的本地修改

如果你想放弃更改
git clean -df
git checkout -- .
git clean删除所有未跟踪的文件(警告:虽然它不会删除直接在.gitignore中提到的被忽略的文件,它可能会删除文件夹中被忽略的文件),git checkout将清除所有未经处理的更改。

2. git checkout master切换到主分支(假设你想用master)
3. git pull从主分支拉最后一个提交
4. git status为了检查一切看起来不错

 On branch master Your branch is up-to-date with 'origin/master'. 

正如Chris所指出的那样,我有如下的情况

git symbolic-ref HEAD失败fatal: ref HEAD is not a symbolic ref

然而, git rev-parse refs/heads/master指向我可以恢复的一个很好的提交(在我的情况下,最后一次提交,你可以看到使用git show [SHA]

之后我做了很多乱七八糟的事情,但似乎已经修好了,

git symbolic-ref HEAD refs/heads/master

头重新连接!

当我个人发现自己处于一种情况,当我不在master时候,我做了一些改变(也就是说, HEADmaster之上,而且没有提交之间的任何提交),可能会有帮助:

 git stash # HEAD has same content as master, but we are still not in master git checkout master # switch to master, okay because no changes and master git stash apply # apply changes we had between HEAD and master in the first place 
 git checkout checksum #you could use this to peek previous checkpoints git status # you will see HEAD detached at checksum git checkout master #this moves HEAD to master branch