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

最近的某个时候,我对一些文件进行了重置,以使它们脱离提交阶段,后来又进行了重新base-I,以消除最近的几个本地提交。现在我处于一种我不太理解的状态。

在我的工作区,git日志显示了我所期望的一切——我在正确的火车上,有我不想要的提交,还有新的提交,等等。

但我只是推到了远程存储库,这是不同的——我在rebase中删除的几个提交被推送了,而本地提交的新提交不在那里。

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


当前回答

如果您在master上执行了一些提交,并且只想在那里“向后合并”master(即您希望master指向HEAD),那么一行代码将是:

git checkout -B master HEAD

这将创建一个名为master的新分支,即使它已经存在(这就像移动master,这就是我们想要的)。新创建的分支被设置为指向HEAD,也就是您所在的位置。新的分支已签出,因此之后您将成为master。

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

其他回答

在我的例子中,我运行了gitstatus,我发现我的工作目录中有一些未跟踪的文件。

为了使重新底座工作,我只需要清洁它们(因为我不需要它们)。

而不是执行git签出origin/master

只需执行git结账大师

然后gitbranch将确认您的分支。

首先,让我们澄清HEAD是什么,以及当它被分离时它意味着什么。

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

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

我们有头→ 参考/主管/主管→ 17a02998078923f2d62811326d130代码991d1a95a

分离HEAD时,它直接指向提交,而不是通过分支间接指向提交。你可以把一个独立的HEAD看作是在一个未命名的分支上。

git符号ref HEAD失败,出现致命错误:ref HEAD不是符号refgit-rev-parse HEAD生成17a02998078923f2d62811326d130de991d1a95a由于它不是符号引用,因此必须直接指向提交本身。

我们有头→ 17a02998078923f2d62811326d130代码991d1a95a

使用分离的HEAD需要记住的重要一点是,如果它指向的提交是未被引用的(没有其他引用可以访问它),那么当您签出其他提交时,它将变为“悬空”。最终,这些悬空的提交将通过垃圾收集过程被删除(默认情况下,它们至少保留2周,并且可以通过HEAD的reflog引用而保留更长时间)。

1.使用分离的HEAD进行“正常”工作是非常好的,您只需跟踪正在进行的操作,以避免从重新记录中提取掉的历史。


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

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

git branch temp
git checkout temp

(这两个命令可以缩写为gitcheckout-b temp)

这将把HEAD重新连接到新的临时分支。

接下来,您应该将当前提交(及其历史记录)与预期要处理的正常分支进行比较:

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

(您可能希望尝试使用日志选项:add-p、off--pretty=…查看整个日志消息等)

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

git branch -f master temp
git checkout master

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

然后可以删除临时分支:

git branch -d temp

最后,您可能希望推动重建的历史:

git push origin master

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

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

简单地说,分离的HEAD状态意味着您没有签出任何分支的HEAD(或提示)。

通过示例了解

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

提交1:主-->分支_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

提交2:主-->123be6a76168aca712aea16076e971c23835f8ca-->分支_HEAD

如上所述,在提交序列的情况下,分支指向最近的提交。因此,在这种情况下,如果您签出提交123be6a76168aca712aea16076e971c23835f8ca,那么您将处于分离的头部状态,因为分支的head指向100644a76168ca712aea16086e971c2 3835f8Ca,从技术上讲,您在没有分支的HEAT签出。因此,您处于分离的HEAD状态。

理论解释

在这个博客中,它清楚地指出Git存储库是一个提交树,每个提交都指向其祖先,每个提交指针都会更新,指向每个分支的这些指针都存储在.Git/refs子目录中。标记存储在.git/refs/Tags中,分支存储在.gt/refs/heads中。如果您查看任何文件,您都会发现每个标记对应一个文件,具有40个字符的提交哈希,正如@Chris Johnsen和@Yaroslav Nikitenko所解释的,您可以查看这些引用。

我也有同样的问题。我把零钱藏在git stash并将本地的分支硬重置为先前的提交(我认为这是导致的),然后执行git pull,我现在无法将其头部分离。别忘了git stash再次申请更改。