如何将 HEAD 移回以前的位置? (分离头)和撤消提交

How can I move HEAD back to a previous location? (Detached head) & Undo commits

在 Git 中,我试图通过合并到另一个分支然后通过以下方式将 HEAD 重置到之前的位置来执行 squash commit

git reset origin/master

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

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

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

First of all what is HEAD?

HEAD 只是对当前分支上当前提交(最新)的引用。
在任何给定时间只能有一个 HEAD(不包括 git 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 to 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.
  • 注意:(Since Git 2.7)您也可以使用git rebase --no-autostash


git revert <sha-1>

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

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

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

使用git checkout -

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


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


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


更有条理的解决方案(两步,但令人难忘)

快速方法解决了 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> 都会提供额外的说明。

问题可以理解为:

我在 23b6772 处与 HEAD 处于分离状态并键入 git reset origin/master(因为我想挤压)。现在我改变了主意,如何回到 HEAD23b6772?

直截了当的答案是:git reset 23b6772

但我遇到了这个问题,因为每次我想引用之前的 HEAD 时,我都厌倦了键入(复制和粘贴)提交哈希或其缩写,并且正在谷歌搜索以查看是否有任何类型的shorthand.

原来有!

git reset -(或者在我的情况下 git cherry-pick -

顺便说一下,这与 cd - 到 return 到前一个 当前目录 在 *nix 中是一样的!太棒了,一石二鸟

本地第一个reset

git reset 23b6772

要查看您的位置是否正确,请验证:

git status

您会看到如下内容:

On branch master Your branch is behind 'origin/master' by 17 commits, and can be fast-forwarded.

然后在您的远程跟踪分支 上重写历史记录以反映更改:

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

使用 --force-with-lease instead of --force will raise an error if others have meanwhile committed to the remote branch, in which case you should fetch first. More info in this article.

当您 运行 命令 git checkout commit_id 时,HEAD 与 13ca5593d(say commit-id) 分离,分支将不再可用。

返回上一个位置 运行 命令步骤 -

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

您将返回到先前的位置,并从远程存储库更新提交。

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

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

然后

git checkout <My-remote-branch>

然后

git pull

我终于得到了我在 detach HEAD 中所做的所有更改。

这可能不是技术解决方案,但它确实有效。 (如果你的队友在本地有相同的分支)

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

解决步骤:

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

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

将最后一个未推送的提交移至新分支

如果您的问题是您开始在 WRONG_BRANCH 上提交,并且想将那些最后的非推送提交移动到 RIGHT_BRANCH,最简单的做法是

  1. git checkout WRONG_BRANCH
  2. git branch RIGHT_BRANCH
  3. git reset —-hard LAST_PUSHED_COMMIT
  4. git checkout RIGHT_BRANCH

在这一点上,如果你 运行 git log HEAD 你会看到你所有的提交都在那里,在 RIGHT_BRACH.

数据

  • WRONG_BRANCH 是您提交的更改(尚未推送)现在所在的位置
  • RIGHT_BRANCH 是您提交的更改(尚未推送)
  • LAST_PUSHED_COMMIT 是您要将 WRONG_BRANCH 恢复为
  • 的位置