git - 如何协调分离的 HEAD 与 master/origin?

标签 git

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

最近的某个地方,我重置了一些文件以使它们退出提交暂存,后来又做了一个 rebase -i摆脱最近的几个本地提交。现在我处于一种我不太明白的状态。

在我的工作区,git log显示了我所期望的——我在正确的火车上,有我不想消失的提交,还有新的提交,等等。

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

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

最佳答案

首先澄清一下what HEAD is以及分离时的含义。

HEAD 是当前 check out 提交的符号名称。当 HEAD 没有分离时(“正常”1 情况:你有一个分支被 check out ),HEAD 实际上指向一个分支的“ref”,而分支指向提交。 HEAD 因此“附加”到一个分支。当您进行新提交时, HEAD 指向的分支将更新为指向新提交。 HEAD 会自动跟随,因为它只是指向分支。

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

  • 我们有 HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a
    当 HEAD 被分离时,它直接指向一个提交——而不是通过一个分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名分支上。
  • git symbolic-ref HEAD失败 fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD yield 17a02998078923f2d62811326d130de991d1a95a由于它不是符号引用,因此它必须直接指向提交本身。

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

    1
    用一个独立的 HEAD 做“正常”的工作是完全没问题的,你只需要跟踪你正在做的事情,以避免不得不从 reflog 中获取丢弃的历史记录。

    交互式 rebase 的中间步骤是通过分离的 HEAD 完成的(部分是为了避免污染事件分支的 reflog)。如果您完成完整的 rebase 操作,它将使用 rebase 操作的累积结果更新您的原始分支,并将 HEAD 重新附加到原始分支。我的猜测是你从未完全完成 rebase 过程;这将为您留下一个分离的 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 操作,您可能应该将其清理干净。您可以通过查找目录 .git/rebase-merge/ 来检查 rebase 是否正在处理中。 .您可以通过删除该目录来手动清理正在进行的 rebase (例如,如果您不再记得事件 rebase 操作的目的和上下文)。通常你会使用 git rebase --abort ,但这会进行一些您可能想要避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们上面所做的一些工作)。

    关于git - 如何协调分离的 HEAD 与 master/origin?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5772192/

    相关文章:

    Git merge 与 Yaml 文件冲突

    Git push origin master 返回 Error cannot spawn ... 为什么?

    git - 在git中解析 "CONFLICT (delete/modify)"

    svn - Git svn 工作流程,在 git-svn 中创建分支

    Git - 如何删除远程仓库中同名的两个文件夹之一

    git - 在 PowerShell 中为 git 命令创建别名?

    git - 如何 git cherry-pick commit 声明我们的历史包含它

    git - 执行 git stash 不会删除 git local 中的更改

    android - 版本控制 Android/Eclipse 项目及其所有第 3 方库

    Git:克隆项目时未 pull 子模块