git reset --hard 和 git checkout 之间的区别

Difference between git reset --hard and git checkout

假设我想撤消之前提交引入的所有更改。

据我了解,git reset --hard <specified commit> 将删除指定提交之前的所有提交,并撤消所有更改。
另一方面 git checkout <specified commit> 将更改我的目录以反映指定的提交。

所以如果我在 git checkout 之后 git reset 会得到与 git reset --hard 相同的结果吗?

或者,如果我在 git checkout 之后简单地 git commit,新创建的提交是否会覆盖现有的提交?

简而言之,git 提交是一棵树,分支只是指向某些提交的指针。

git checkout <specified commit>不移动分支指针。当你这样做时,你处于分离的头部状态。您将看到这条消息,它非常不言自明:

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

另一个区别是 git checkout 更安全,因为它不会拒绝您在工作树中的更改,并且您不会丢失任何提交¹。

另一方面,

git reset --hard <specified commit> 会将您当前的分支移动到指定的提交,并且 您将丢失工作树中的所有更改。此外,如果您要移动到一些较旧的提交,而较新的提交不在其他分支中,您也会丢失这些较新的提交。这不是一个安全的操作,除非你真的明白你在做什么,否则不要这样做。

另请参阅 these great answers 了解有关如何撤消 git 提交的信息。

您可能还会受益于使用 SourceTree 等 GUI 工具。


¹ - 好吧,除非你在一些悬而未决的提交上已经处于超然状态,但通常你不应该担心。

So if I git reset after git checkout will it have the same result as git reset --hard?

没有。 git reset(使用 --hard 或任何其他选项)重置 HEAD,因此您总是会丢失提交,除非您没有指定要重置为的任何提交。

执行 git checkout <commit> 后,您处于分离的 HEAD 状态,因此 git reset 有点毫无意义,因为您不会重置任何分支。

Alternatively, if I simply git commit after git checkout, will the newly created commit overwrite the existing commits?

没有。因为再次处于分离的 HEAD 状态。您实际上是在幽灵分支中创建提交。

最安全的做法是始终使用 git checkout -b 创建一个新分支,一旦您确定要重置其他分支,然后执行 git reset --hard.