Git:如何撤销提交并还原到上一分支

7

哎呀...我错误地提交了一个相当复杂的更改(包括子目录和文件重命名),并不真正知道自己在做什么(或Git会做什么)。

现在我想撤销所有内容,使其满足以下条件:

  1. 提交完全被撤销(就像从未完成一样,可能也将其从历史记录中删除)
  2. 将当前工作目录(其中包含 .git)恢复到某个分支(最后一个分支即可)。

我找到了关于 git reset --softgit reset --hard 的参考资料,但我已经向自己证明,如果过早地使用命令而不完全理解它,我可以造成真正的损害。 :)

我找到了 git reset man page,但我仍然感到困惑:

  1. HEAD 是什么?
  2. HEAD* master 有什么区别?
  3. 在我的情况下(见上文),我需要使用 --soft--hard 还是其他(还有 3 种选项)?
  4. 在执行 git reset 后,我需要运行另一个命令来“完成”撤销吗?

更新:阅读下面的答案后:

  1. 我是否正确理解,在我的情况下,我只需要发出一个命令 git reset --hard HEAD^
  2. 如何验证撤销是否已正确执行?

2
既然你正在学习Git,让我向你推荐两本书:Git社区手册Pro Git,它们都是完全在线的。 - shelhamer
2个回答

7
  1. HEAD 是当前分支最新的提交。
  2. master 是一个分支(通常是主分支),而 HEAD 是所检出分支历史上的一个位置。 HEAD 相对于你所在的分支。
  3. git reset --soft 会将更改保留在工作树中,未提交,您可以随意处理。 git reset --hard 将恢复工作树到您重置到的提交状态。
  4. 不需要其他命令。

首先,为了保留提交以便稍后检查,创建一个分支:

git checkout -b my_bad_commit

或者按照larsman评论中提到的方法执行git branch my_bad_commit

然后返回到master或其他你所在的分支并进行重置:

git checkout branch_with_bad_commit
git reset --hard HEAD^

HEAD^ 翻译为“HEAD的父级”,您甚至可以叠加使用 HEAD^^ = 2个提交向后。有关此主题的更多信息,请查看git社区书籍中有关撤消操作的章节。


1
checkout -b; checkout 序列可以使用单个 branch 命令完成。 - Fred Foo
提到这一点很好。我有很多别名,所以我只需使用 git cob new_branch_name 就会有时忘记真正的别名。 - shelhamer
@Shelhamer 在执行 git checkout mastergit reset --hard HEAD^ 两条命令后,我回到了两个提交之前,这不是我想要的。我只需要回到一个提交之前。可能是我的问题表述不够清晰。 - WinWin
1
@WinWin,如果您的主分支没有包含错误提交,可能存在一些沟通问题(这就是我说“...或者您所在的任何一个分支”的原因,意思是检出该分支)。如果您需要恢复丢失的历史记录,请使用 git reflog 进行恢复。它将列出以前的 HEAD,您可以检出或重置它们。 - shelhamer
@Shelhamer 感谢您的 git reflog 提示。书籍链接是无价的。虽然需要时间来消化它们。我仍然不确定为什么仅使用 git reset --hard HEAD^ 就不足够了(因为我真的不想保留提交记录。这就是重点)。 - WinWin
@WinWin,在你的问题中提到了想要保留提交的选项(也许是从历史记录中删除或不删除)。如果你真的不在意这个提交,你可以在有问题的分支上执行 git reset --hard HEAD^ 命令,将 HEAD 指向坏提交之前的提交,就好像坏提交从未存在过一样。 - shelhamer

1
  1. HEAD 是当前分支的顶端
  2. HEADmaster 的区别在于,当你切换分支(或提交)时,HEAD 会发生变化。
  3. --soft 会保留更改,因此您可以重新添加/提交它们或通过对更改文件执行 git checkout 来撤消它们。 --hard 将工作区重置为您要重置到的提交状态。
  4. 如果您使用 reset --hard,则需要 git push --force 到远程仓库(尽管,如果您所做的更改已经在远程上了,则强烈不建议重写历史记录)。

谢谢 +1。幸运的是,我还没有推送任何东西。所以,git reset --hard HEAD^ 就足够了吗? - WinWin
2
如果你只想撤销最后一次提交,可以使用 git reset --hard 命令。为了保险起见,在执行该命令之前,你也可以使用 git branch mistake 命令创建一个备份分支;如果出现任何问题,你可以使用 git merge mistake 命令将错误的提交恢复回来。 - Fred Foo
哎呀,使用CVS这么多年后,我感觉在git的世界里完全是个新手。 :) - WinWin
奇怪的是,我从来没有理解过CVS或SVN,但转换到Git感觉像回家一样 ;) - Fred Foo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接