如何将HEAD移回先前的位置?(独立的头部)和撤消提交


179

在Git中,我试图squash commit通过合并到另一个分支中然后重置HEAD为先前的位置来进行操作:

git reset origin/master

但我需要走出这一步。如何将HEAD移回先前的位置?

我有23b6772提交所需的SHA-1片段()。我怎样才能回到这个提交?


11
HEAD只是指向您当前位置的指针(确切地说是修订版本)。git checkout 23b6772应该做。
Yaroslav Admin


1
@YaroslavAdmin没有它应该不会。直接检出提交发生分离的HEAD状态的原因(因为远程跟踪分支本身无法检出,并且像OP那样自动延迟到它们指向的提交时),也很抱歉评论:-)我有点希望最初的问题已经解决...
RomainValeri

Answers:


394

在回答之前,让我们添加一些背景,解释一下这HEAD是什么。

First of all what is HEAD?

HEAD只是对当前分支上当前提交(最新)的引用。在任何给定时间(除外)
只能有一个。HEADgit worktree

的内容HEAD存储在内部.git/HEAD,它包含当前提交的40个字节的SHA-1。


detached HEAD

如果您不在最新的提交上-这意味着HEAD指向历史上的先前提交,则称为detached HEAD

在此处输入图片说明

在命令行上,它看起来像这样-SHA-1而不是分支名称,因为HEAD并不指向当前分支的尖端:

在此处输入图片说明

在此处输入图片说明


有关如何从分离的HEAD中恢复的几种选择:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

这将签出指向所需提交的新分支。
该命令将签出给定的提交。
此时,您可以创建一个分支并从此开始工作。

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

您也可以随时使用reflog
git reflog 将显示任何更新的更改,HEAD并签出所需的reflog条目,将HEAD后退设置为此提交。

每次修改HEAD时,都会在 reflog

git reflog
git checkout HEAD@{...}

这将使您回到所需的提交

在此处输入图片说明


git reset --hard <commit_id>

将“ HEAD”“移动”回所需的提交。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • 注意:(自Git 2.7起),您也可以使用git rebase --no-autostash

git revert <sha-1>

“撤消”给定的提交或提交范围。
reset命令将“撤消”在给定提交中所做的任何更改。
带有撤消补丁的新提交将被提交,而原始提交也将保留在历史记录中。

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

该模式说明了哪个命令可以执行什么操作。
如您所见,reset && checkout修改HEAD

在此处输入图片说明


如果您不在最新提交上-意味着HEAD指向历史记录中的先前提交,则称为分离的HEAD,除非该历史记录中的先前提交是另一个分支的提示。以我的经验,您可以说,如果HEAD不指向任何分支也指向的提交,则您是分离的。这不适用于标签。
蒂姆(Tim)

您可以处于分离的HEAD中,并且同时具有与此分支的HEAD相同提交的分支。我不明白您的评论
CodeWizard

3
您在标题中使用行内代码标记时
遇到了问题

无法找到任何更好的方式来强调它。随时进行编辑。您非常欢迎
CodeWizard

22

git reset 23b6772

查看您的位置是否正确:

git status

你会看到一些东西

在分支母版上您的分支落后“起源/母版” 17次提交,并且可以快速转发。

然后在您的遥控器上重写历史记录以反映更改:

git push --force-with-lease // a useful command @oktober mentions in comments

1
格外谨慎git push --force。在许多情况下,它会使你对球队最不受欢迎的人一会儿....
凯V

要添加到上述注释中,我刚刚在about.gitlab.com/blog/2014/11/26/keeping-your-code-protected处遇到了这句话,并不得不添加它:“一个git push --force命令可以轻易地破坏很多人的生活:[186 Jenkins]信息库的分支头倒转以指向较旧的提交,实际上,较新的提交在错误的git-push之后被放错了位置。” --very不受欢迎开发商....
凯V

2
@KayV看一看git push --force-with-lease(Thoughtbot文章:Thoughtbot.com/blog/git-push-force-with-lease
10

1
有用的标志,@ oktober,以及一篇不错的文章。感谢您在此处添加它并对其进行ping操作。

1
谢谢!这帮助我取消了糟糕的合并。因为合并对revert提交的反应不同,所以我发现自己处于极其困难的境地。force-with-lease让我有信心重写分支的git历史记录,而又不影响其他人的工作。太棒了!
anon58192932

11

最快的解决方案(只需1步)

git checkout -

你会看到的Switched to branch <branch_name>。确认这是您想要的分支。


简要说明:该命令会将HEAD返回其最后位置。请参阅此答案末尾关于结果的注释。


助记符:这种方法很像cd -用来返回到您以前访问过的目录。语法和适用的情况非常匹配(例如,当您实际上希望HEAD返回到原来的位置时,这很有用)。


更有条理的解决方案(两步操作,但值得纪念)

快速方法解决了OP的问题。但是,如果您的情况稍有不同,该怎么办:假设您已重新启动Bash,然后发现HEAD已分离。在这种情况下,这里有2个简单易记的步骤。

1.选择您需要的分支

git branch -v

您会看到现有本地分支机构的列表。获取适合您需求的分支名称。

2.将HEAD移动到它

git checkout <branch_name>

你会看到的Switched to branch <branch_name>。成功!


结果

无论采用哪种方法,您现在都可以像以前一样继续添加和提交工作:在上跟踪您的下一次更改<branch_name>

请注意,如果您在分离HEAD时提交了更改,则git checkout -git checkout <branch_name>都将提供其他说明。


这不是工作,因为如果我这样做(假设8acc968是HEAD〜2)git checkout 8acc968git branch -vMyBranch以下...列表中,但随后git checkout MyBranch删除我的意见。
amuliar

嗨@amuliar- git checkout 8acc968将签出一个提交,而不是一个分支。如果MyBranch有所需的提交,请尝试git checkout MyBranch。如果它不包含落实8acc968中的更改,则需要在签出分支之后合并这些更改。
凯五世

感谢你的回答!我确实git checkout看到了先前的提交,并且想回到最新的提交。但是没有最新的提交哈希,我几乎迷失了。该解决方案非常适合我的情况!
zyy

4

问题可以理解为:

我与HEADat 处于分离状态23b6772并输入了git reset origin/master(因为我想压扁)。现在我改变了主意,我该如何回到原来的HEAD状态23b6772

最简单的答案是: git reset 23b6772

但是我遇到了这个问题,因为每次我想引用以前的版本时,我都讨厌键入(复制和粘贴)提交哈希或它的缩写 HEAD并且谷歌搜索是否存在任何速记形式。

原来有!

git reset - (或者就我而言 git cherry-pick -

顺便说一句,它与cd -返回* nix中的前一个当前目录相同!所以hurrah,我用一块石头学了两件事。


0

当您运行命令时git checkout commit_id13ca5593d(say commit-id)与HEAD分离的HEAD 和分支将处于可用状态。

返回到先前的位置,明智地运行命令-

  1. git pull origin branch_name (说大师)
  2. git checkout branch_name
  3. git pull origin branch_name

您将通过远程存储库中的更新提交返回到先前的位置。


0

今天,我错误地签出了一个提交,然后开始进行处理,在分离的HEAD状态下进行了一些提交。然后,我使用以下命令推送到远程分支:

git push origin HEAD: <My-remote-branch>

然后

git checkout <My-remote-branch>

然后

git pull

我终于在分支HEAD中进行了所有更改。


0

这可能不是技术解决方案,但可以。(如果您的队友在本地拥有相同的分支机构)

假设您的分支名称为branch-xxx

解决步骤:

  • 不要更新或拉-没有
  • 只需在他的机器上从branch-xxx创建一个新分支(branch-yyy
  • 就是这样,您现有的所有更改都将在此新分支(branch-yyy)中。您可以在此分支继续工作。

注意:同样,这不是技术解决方案,但是肯定会有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.