我怎样才能调和分离的HEAD与主/来源? [英] How can I reconcile detached HEAD with master/origin?

查看:115
本文介绍了我怎样才能调和分离的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

    名为master的分支已签出。

  • git rev-parse refs / heads / master yield 17a02998078923f2d62811326d130de991d1a95a

    该提交是当前提示或头部。
  • git rev-parse HEAD 也会产生 17a02998078923f2d62811326d130de991d1a95a

    这就是符号参考的含义。它通过一些其他引用指向一个对象。

    (符号引用最初是作为符号链接实现的,但后来更改为带有额外解释的纯文本,以便可以在没有符号链接的平台上使用它们。 )



我们有 HEAD refs / heads / master 17a02998078923f2d62811326d130de991d1a95a



当HEAD分离时,它直接指向提交而不是间接指向一个分支。你可以将分离的HEAD想象成一个未命名的分支。
$ b


  • git symbolic-ref HEAD 失败,致命: ref HEAD不是符号ref

  • git rev-parse HEAD 产生 17a02998078923f2d62811326d130de991d1a95a

    由于它不是符号引用,它必须直接指向提交本身。



我们有 HEAD 17a02998078923f2d62811326d130de991d1a95a



用分离的HEAD记住的重要事情是,如果它指向的提交不是其他的引用(其他引用无法达到它),那么当你签出其他提交时它将变成悬挂。最后,这些悬而未决的提交将通过垃圾收集过程进行修剪(默认情况下,它们会保留至少2周,并且可能会被HEAD的引用日志引用而延长)。

1
使用分离式HEAD进行正常工作是完全正确的,您只需跟踪自己在做什么以避免必须将丢失的历史记录从




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



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

$ g $ branch $ temp $ b $ git checkout temp

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

这会将HEAD重新附加到新的 temp 分支中。

>

接下来,您应该将当前提交(及其历史记录)与您希望工作的普通分支进行比较:

  git log --graph --decorate --pretty = oneline --abbrev-commit主起源/主temp 
git diff主temp
git差异原点/ master temp

(您可能想试验日志选项:add -p ,请忽略 - pretty = ...

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

  git branch -f master temp 
git checkout master

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



您可以删除临时分支:

  git分支-d temp 

最后,您可能会想要重新建立历史记录:

  git push origin master 

您可能需要将 - force 添加到如果远程分支不能被快进到新的提交(即,你删除或重写了一些现有的提交,或者重写了一些历史记录)。

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


I'm new at the branching complexities of Git. I always work on a single branch and commit changes and then periodically push to my remote origin.

Somewhere recently, I did a reset of some files to get them out of commit staging, and later did a rebase -i to get rid of a couple recent local commits. Now I'm in a state I don't quite understand.

In my working area, git log shows exactly what I'd expect-- I'm on the right train with the commits I didn't want gone, and new ones there, etc.

But I just pushed to the remote repository, and what's there is different-- a couple of the commits I'd killed in the rebase got pushed, and the new ones committed locally aren't there.

I think "master/origin" is detached from HEAD, but I'm not 100% clear on what that means, how to visualize it with the command line tools, and how to fix it.

解决方案

First, let’s clarify what HEAD is and what it means when it is detached.

HEAD is the symbolic name for the currently checked out commit. When HEAD is not detached (the "normal"1 situation: you have a branch checked out), HEAD actually points to a branch’s "ref" and the branch points to the commit. HEAD is thus "attached" to a branch. When you make a new commit, the branch that HEAD points to is updated to point to the new commit. HEAD follows automatically since it just points to the branch.

  • git symbolic-ref HEAD yields refs/heads/master
    The branch named "master" is checked out.
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a
    That commit is the current tip or "head" of the master branch.
  • git rev-parse HEAD also yields 17a02998078923f2d62811326d130de991d1a95a
    This is what it means to be a "symbolic ref". It points to an object through some other reference.
    (Symbolic refs were originally implemented as symbolic links, but later changed to plain files with extra interpretation so that they could be used on platforms that do not have symlinks.)

We have HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

When HEAD is detached, it points directly to a commit—instead of indirectly pointing to one through a branch. You can think of a detached HEAD as being on an unnamed branch.

  • git symbolic-ref HEAD fails with fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD yields 17a02998078923f2d62811326d130de991d1a95a
    Since it is not a symbolic ref, it must point directly to the commit itself.

We have HEAD17a02998078923f2d62811326d130de991d1a95a

The important thing to remember with a detached HEAD is that if the commit it points to is otherwise unreferenced (no other ref can reach it), then it will become "dangling" when you checkout some other commit. Eventually, such dangling commits will be pruned through the garbage collection process (by default, they are kept for at least 2 weeks and may be kept longer by being referenced by HEAD’s reflog).

1 It is perfectly fine to do "normal" work with a detached HEAD, you just have to keep track of what you are doing to avoid having to fish dropped history out of the reflog.


The intermediate steps of an interactive rebase are done with a detached HEAD (partially to avoid polluting the active branch’s reflog). If you finish the full rebase operation, it will update your original branch with the cumulative result of the rebase operation and reattach HEAD to the original branch. My guess is that you never fully completed the rebase process; this will leave you with a detached HEAD pointing to the commit that was most recently processed by the rebase operation.

To recover from your situation, you should create a branch that points to the commit currently pointed to by your detached HEAD:

git branch temp
git checkout temp

(these two commands can be abbreviated as git checkout -b temp)

This will reattach your HEAD to the new temp branch.

Next, you should compare the current commit (and its history) with the normal branch on which you expected to be working:

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

(You will probably want to experiment with the log options: add -p, leave off --pretty=… to see the whole log message, etc.)

If your new temp branch looks good, you may want to update (e.g.) master to point to it:

git branch -f master temp
git checkout master

(these two commands can be abbreviated as git checkout -B master temp)

You can then delete the temporary branch:

git branch -d temp

Finally, you will probably want to push the reestablished history:

git push origin master

You may need to add --force to the end of this command to push if the remote branch can not be "fast-forwarded" to the new commit (i.e. you dropped, or rewrote some existing commit, or otherwise rewrote some bit of history).

If you were in the middle of a rebase operation you should probably clean it up. You can check whether a rebase was in process by looking for the directory .git/rebase-merge/. You can manually clean up the in-progress rebase by just deleting that directory (e.g. if you no longer remember the purpose and context of the active rebase operation). Usually you would use git rebase --abort, but that does some extra resetting that you probably want to avoid (it moves HEAD back to the original branch and resets it back to the original commit, which will undo some of the work we did above).

这篇关于我怎样才能调和分离的HEAD与主/来源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆