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

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

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

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

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


当前回答

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

git checkout -B master HEAD

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

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

其他回答

首先,让我们澄清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移回原始分支,并将其重置回原始提交,这将撤消我们上面所做的一些工作)。

查看此处了解分离头部的基本说明:

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

使其可视化的命令行:

git branch

or

git branch -a

您将得到如下输出:

* (no branch)
master
branch1

*(无分支)表示您处于分离状态。

您可以通过执行git checkout somecommit等来达到此状态,它会警告您以下内容:

您处于“分离HEAD”状态。你可以四处看看,做实验更改并提交它们,您可以放弃你在这方面的任何承诺状态而不影响任何分支通过执行另一次结账。如果要创建新分支到保留您创建的提交,您可以这样做所以(现在或以后)使用-b和再次执行checkout命令。例子:git checkout-b new_branch_name

现在,要让他们找到主人:

执行git reflog,甚至只执行git log,并记录您的提交。现在git checkout master和git合并提交。

git merge HEAD@{1}

编辑:

此外,使用gitrebase-i不仅可以删除/删除不需要的提交,还可以编辑它们。只需在提交列表中提到“edit”,您就可以修改提交,然后发出gitrebase——继续。这将确保你永远不会进入一个分离的头部。

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

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

所以我做到了:

git branch -d branchname

然后再次检查分支:

git checkout branchname

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

git符号ref HEAD失败,出现致命错误:ref HEAD不是符号ref

然而,git rev parse refs/heads/master指向了一个好的提交,我可以从中恢复(在我的案例中,最后一次提交,您可以通过使用git show[SHA]看到该提交)

在那之后我做了很多乱七八糟的事情,但似乎已经解决了,

git符号ref HEAD refs/heads/master

头部重新连接!