ChatGPT解决这个技术问题 Extra ChatGPT

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

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

git reset origin/master

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

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

HEAD 只是指向您当前位置的指针(或准确地说是修订版)。 git checkout 23b6772 应该这样做。
@YaroslavAdmin 不,不应该。直接签出提交是发生分离 HEAD 状态的原因(因为远程跟踪分支无法自行签出并自动推迟到当您尝试这样做时它们指向的提交,就像 OP 所做的那样)另外,对于死灵法师表示抱歉评论:-)我有点希望最初的问题已经解决了......

C
CodeWizard

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

首先什么是HEAD?

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

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

分离头

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

https://i.stack.imgur.com/OlavO.png

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

https://i.stack.imgur.com/qplvo.png

https://i.stack.imgur.com/U0l3s.png

关于如何从分离的 HEAD 中恢复的一些选项:

git结帐

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@{...}

这将使您回到所需的提交

https://i.stack.imgur.com/atW9w.png

git reset --hard

将您的 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。

https://i.stack.imgur.com/iyaGj.png

git revert

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

# 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

https://i.stack.imgur.com/NuThL.png


如果您不是最新的提交 - 这意味着 HEAD 指向历史中的先前提交,它称为分离的 HEAD,除非历史中的先前提交是不同分支的尖端。根据我的经验,如果 HEAD 没有指向任何分支也指向的提交,你可以说你是分离的。这不适用于标签。
您可以在分离的 HEAD 中,同时拥有与该分支的 HEAD 具有相同提交的分支。我不明白你的评论
我对您对标题使用内联代码标记有疑问:)
找不到更好的方法来强调它。随意编辑。非常欢迎你
P
Pallav Jha

本地第一个 reset

git reset 23b6772

要查看您是否处于正确的位置,请通过以下方式验证:

git status

你会看到类似的东西:

在分支 master 您的分支在 'origin/master' 之后 17 次提交,并且可以快进。

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

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

如果其他人同时提交到远程分支,使用 --force-with-lease 而不是 --force 将引发错误,在这种情况下您应该先获取。 More info in this article


git push --force 格外小心。在许多情况下,它会让你在一段时间内成为团队中最不受欢迎的人......
添加到上面的注释中,我刚刚在 about.gitlab.com/blog/2014/11/26/keeping-your-code-protected 看到了这句话,不得不添加它:“一个 git push --force 命令很容易毁掉很多人的一天:[186 Jenkins] 存储库有他们的分支头倒带指向较旧的提交,实际上新的提交在错误的 git-push 之后放错了位置。” --非常不受欢迎的开发者....
@KayV 看看 git push --force-with-lease(Thoughtbot 文章:thoughtbot.com/blog/git-push-force-with-lease
有用的标志,@oktober 和一篇好文章。感谢您在此处添加它并通知我。
谢谢你!这帮助我取消了错误的合并。由于合并对 revert 的反应与提交不同,因此我发现自己处于极其困难的境地。 force-with-lease 让我有信心在不影响其他人工作的情况下重写分支的 git 历史。太棒了!
K
Kay V

最快的解决方案(只需 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 8acc968,那么 git branch -v 在下面的列表中有 MyBranch ...但是 git checkout MyBranch 会删除我的评论。
嗨@amuliar - git checkout 8acc968 将检查提交,而不是分支。如果 MyBranch 有您想要的提交,请尝试 git checkout MyBranch。如果它不包含提交 8acc968 中的更改,则需要在签出分支后合并这些更改。
感谢你的回答!我执行 git checkout 是为了查看以前的提交,并想回到最新的提交。但是没有最新的提交哈希,我几乎迷路了。这个解决方案非常适合我的情况!
git checkout -不一定有你说的效果。
P
Peter Mortensen

这个问题可以解读为:

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

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

但是我遇到了这个问题,因为每次我想引用前一个 HEAD 时,我都厌倦了输入(复制和粘贴)提交哈希或其缩写,并且在谷歌上搜索是否有任何速记。

原来有!

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

顺便说一句,这与在 *nix 中返回上一个 当前目录cd - 相同!太棒了,我用一块石头学到了两件事。


P
Peter Mortensen

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

移回以前的位置,逐步运行命令 -

git pull origin branch_name(比如 master) git checkout branch_name git pull origin branch_name

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


P
Peter Mortensen

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

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

然后

git checkout <My-remote-branch>

然后

git pull

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


S
Sathish Kumar

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

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

解决步骤:

不要更新或拉动 - 什么都不要

只需在他的机器上从 branch-xxx 创建一个新分支(branch-yyy)

就是这样,您现有的所有更改都将在这个新分支(branch-yyy)中。您可以继续使用此分支进行工作。

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


a
aercolino

将最后一个非推送的提交移动到新分支

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

git checkout WRONG_BRANCH git branch RIGHT_BRANCH git reset —-hard LAST_PUSHED_COMMIT git checkout RIGHT_BRANCH

此时,如果您运行 git log HEAD,您将看到您的所有提交都在 RIGHT_BRACH 中。

数据

WRONG_BRANCH 是您提交的更改(尚未推送)现在所在的位置

RIGHT_BRANCH 是您提交的更改(尚未推送)的位置

LAST_PUSHED_COMMIT 是您要将 WRONG_BRANCH 恢复到的位置