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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5772192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 10:45:05  来源:igfitidea点击:

How can I reconcile detached HEAD with master/origin?

git

提问by Ben Zotto

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.

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

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

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

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

在我的工作区域,git log显示了我所期望的——我在正确的火车上,我不想要的提交,以及新的提交,等等。

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.

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

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.

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

回答by Chris Johnsen

First, let's clarify what HEAD isand what it means when it is detached.

首先,让我们澄清一下 HEAD 是什么以及它分离时的含义。

HEAD is the symbolic name for the currently checked out commit. When HEAD is not detached (the “normal”1situation: 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.

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

  • git symbolic-ref HEADyields refs/heads/master
    The branch named “master” is checked out.
  • git rev-parse refs/heads/masteryield 17a02998078923f2d62811326d130de991d1a95a
    That commit is the current tip or “head” of the master branch.
  • git rev-parse HEADalso 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.)
  • git symbolic-ref HEADyieldsrefs/heads/master
    名为“master”的分支被检出。
  • git rev-parse refs/heads/masteryield17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或“头”。
  • git rev-parse HEAD也产生17a02998078923f2d62811326d130de991d1a95a
    这就是“符号引用”的意思。它通过其他一些引用指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来改为带有额外解释的纯文件,以便它们可以在没有符号链接的平台上使用。)

We have HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

我们有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.

当 HEAD 被分离时,它直接指向一个提交——而不是通过一个分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名分支上。

  • git symbolic-ref HEADfails with fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEADyields 17a02998078923f2d62811326d130de991d1a95a
    Since it is not a symbolic ref, it must point directly to the commit itself.
  • git symbolic-ref HEAD失败 fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEADyields17a02998078923f2d62811326d130de991d1a95a
    因为它不是一个符号引用,所以它必须直接指向提交本身。

We have HEAD17a02998078923f2d62811326d130de991d1a95a

我们有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).

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

1It 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.

1用一个分离的 HEAD 做“正常”的工作是完全没问题的,你只需要跟踪你正在做的事情,以避免不得不从 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.

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

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

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

git branch temp
git checkout temp

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

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

This will reattach your HEAD to the new tempbranch.

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

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.)

(您可能想尝试使用日志选项:添加-p、离开--pretty=…以查看整个日志消息等。)

If your new tempbranch looks good, you may want to update (e.g.) masterto point to it:

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

git branch -f master temp
git checkout master

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

(这两个命令可以简写为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 --forceto 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).

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

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).

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

回答by Daniel Alexiuc

Just do this:

只需这样做:

git checkout master

Or, if you have changes that you want to keep, do this:

或者,如果您有要保留的更改,请执行以下操作:

git checkout -b temp
git checkout -B master temp

回答by Dmitry Minkovsky

I ran into this issue and when I read in the top voted answer:

我遇到了这个问题,当我读到投票最高的答案时:

HEAD is the symbolic name for the currently checked out commit.

HEAD 是当前检出提交的符号名称。

I thought: Ah-ha! If HEADis the symbolic name for the currenlty checkout commit, I can reconcile it against masterby rebasing it against master:

我想:啊哈!如果HEAD是当前结帐提交的符号名称,我可以通过将其master重新设置为对它进行协调master

git rebase HEAD master

This command:

这个命令:

  1. checks out master
  2. identifies the parent commits of HEADback to the point HEADdiverged from master
  3. plays those commits on top of master
  1. 退房 master
  2. 标识HEAD回到HEAD偏离点的父提交master
  3. 在上面播放这些提交 master

The end result is that all commits that were in HEADbut not masterare then also in master. masterremains checked out.

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



Regarding the remote:

关于遥控器:

a couple of the commits I'd killed in the rebase got pushed, and the new ones committed locally aren't there.

我在 rebase 中杀死的一些提交被推送了,而本地提交的新提交不存在。

The remote history can no longer be fast-forwarded using your local history. You'll need to force-push (git push -f) to overwrite the remote history. If you have any collaborators, it usually makes sense to coordinate this with them so everyone is on the same page.

远程历史不能再使用您的本地历史进行快进。您需要强制推送 ( git push -f) 以覆盖远程历史记录。如果您有任何合作者,通常与他们进行协调是有意义的,这样每个人都在同一页面上。

After you push masterto remote origin, your remote tracking branch origin/masterwill be updated to point to the same commit as master.

master送到远程后origin,您的远程跟踪分支origin/master将更新为指向与master.

回答by manojlds

Look here for basic explanation of detached head:

在这里查看分离头的基本解释:

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

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

Command line to visualize it:

命令行可视化它:

git branch

or

或者

git branch -a

you will get output like below:

你会得到如下输出:

* (no branch)
master
branch1

The * (no branch)shows you are in detached head.

* (no branch)表明你处于超然状态。

You could have come to this state by doing a git checkout somecommitetc. and it would have warned you with the following:

你可以通过做一个git checkout somecommit等来达到这个状态,它会警告你以下内容:

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

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

如果你想创建一个新分支来保留你创建的提交,你可以(现在或以后)通过再次使用 -b 和 checkout 命令来这样做。例子:

git checkout -b new_branch_name

Now, to get them onto master:

现在,让他们成为主人:

Do a git reflogor even just git logand note your commits. Now git checkout masterand git mergethe commits.

做一个git reflog或什至只是git log并注意你的提交。现在git checkout mastergit merge提交。

git merge HEAD@{1}

Edit:

编辑:

To add, use git rebase -inot only for deleting / killing commits that you don't need, but also for editing them. Just mention "edit" in the commit list and you will be able to amend your commit and then issue a git rebase --continueto go ahead. This would have ensured that you never came in to a detached HEAD.

添加,git rebase -i不仅用于删除/终止您不需要的提交,还用于编辑它们。只需在提交列表中提及“编辑”,您就可以修改您的提交,然后发出一个git rebase --continue继续。这将确保您永远不会进入分离的 HEAD。

回答by Rose Perrone

Get your detached commit onto its own branch

将你的分离提交放到它自己的分支上

Simply run git checkout -b mynewbranch.

只需运行git checkout -b mynewbranch

Then run git log, and you'll see that commit is now HEADon this new branch.

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

回答by amdev

if you have just master branch and wanna back to "develop" or a feature just do this :

如果您只有 master 分支并想回到“开发”或功能,请执行以下操作:

git checkout origin/develop

Note: checking out origin/develop.

注意:检查origin/develop

You are in detached HEADstate. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout...

您处于分离的 HEAD状态。您可以环顾四周,进行实验性更改并提交它们,并且您可以通过执行另一次检出来丢弃您在此状态下所做的任何提交,而不会影响任何分支......

then

然后

git checkout -b develop

It works :)

有用 :)

回答by kenorb

If you want to push your current detached HEAD (check git logbefore), try:

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

git push origin HEAD:master

to send your detached HEAD into master branch at origin. If your push gets rejected, try git pull origin masterfirst to get the changes from origin. If you don't care about the changes from origin and it's rejected, because you did some intentional rebase and you want to replace origin/master with your currently detached branch - then you may force it (-f). In case you lost some access to previous commits, you can always run git reflogto see the history from all branches.

将分离的 HEAD 发送到原点的 master 分支。如果您的推送被拒绝,请先尝试git pull origin master从原点获取更改。如果您不关心来自 origin 的更改并且它被拒绝,因为您做了一些有意的 rebase 并且您想用当前分离的分支替换 origin/master - 那么您可以强制它(-f)。如果您无法访问以前的提交,您可以随时运行git reflog以查看所有分支的历史记录。



To get back on a master branch, while keeping the changes, try the following commands:

要返回主分支,同时保留更改,请尝试以下命令:

git rebase HEAD master
git checkout master

See: Git: "Not currently on any branch." Is there an easy way to get back on a branch, while keeping the changes?

请参阅:Git:“当前不在任何分支上。” 有没有一种简单的方法可以在保留更改的同时返回分支?

回答by user664833

I found this question when searching for You are in 'detached HEAD' state.

我在搜索时发现了这个问题 You are in 'detached HEAD' state.

After analyzing what I had done to get here, as compared with what I had done in the past, I discovered that I had made a mistake.

分析了自己的所作所为之后,与过去所做的相比,我发现我犯了一个错误。

My normal flow is:

我的正常流程是:

git checkout master
git fetch
git checkout my-cool-branch
git pull

This time I did:

这次我做到了:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.

The problem is that I accidentally did:

问题是我不小心做了:

git checkout origin/my-cool-branch

Rather than:

而不是:

git checkout my-cool-branch

The fix (in my situation) was simply to run the above command and then continue the flow:

修复(在我的情况下)只是运行上述命令,然后继续流程:

git checkout my-cool-branch
git pull

回答by Daniel Porumbel

The following worked for me (using only branch master):

以下对我有用(仅使用分支主):

git push origin HEAD:master
git checkout master        
git pull

The first one pushes the detached HEAD to remote origin.

第一个将分离的 HEAD 推送到远程源。

The second one moves to branch master.

第二个转移到分支主。

The third one recovers the HEAD that becomes attached to branch master.

第三个恢复连接到分支 master 的 HEAD。

Problems might arise at the first command if the push gets rejected. But this would no longer be a problem of detached head, but is about the fact that the detached HEAD is not aware of some remote changes.

如果推送被拒绝,第一个命令可能会出现问题。但这将不再是分离头的问题,而是关于分离头不知道一些远程变化的事实。

回答by adamwineguy

I just ran into this issue today and am pretty sure I solved it by doing:

我今天刚遇到这个问题,很确定我通过以下方式解决了这个问题:

git branch temp
git checkout master
git merge temp

I was on my work computer when I figured out how to do this, and now I'm running into the same problem on my personal computer. So will have to wait till Monday when I'm back at the work computer to see exactly how I did it.

当我想出如何做到这一点时,我在我的工作计算机上,现在我在我的个人计算机上遇到了同样的问题。因此,我必须等到周一回到工作计算机前才能确切了解我是如何做到的。