git checkout 和 git reset 的区别

git checkout 和 git reset 有时候会让新手感到困惑,因为它们的表现很相似,本文就简单分析一下两者的区别。

git checkout 和 git reset 主要有两种使用方式

1、命令后面单独接分支名称(不带文件名和目录)的情况

不接文件名的时候,执行 git checkout [branch] 与执行 git reset --hard [branch] 非常相似,都会更新所有的三棵树,不过有两点重要的区别。

git三棵树(HEAD,暂存区,工作区)
  • 首先不同于 reset --hardcheckout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件弄丢;而 reset --hard 则会不做检查就全面地替换所有文件。
  • 第二个重要的区别是如何更新 HEADreset 会移动 HEAD 分支的指向(即 HEAD 指向分支的指向),而 checkout 只会移动 HEAD 自身来指向另一个分支。

例如,我们有 masterdevelop 分支,它们分别指向不同的提交;我们现在在 develop 上(所以 HEAD 指向它)。 如果我们运行 git reset master,那么 develop 会和 master 指向同一个提交; 而如果我们运行 git checkout master 的话,develop 不会移动,HEAD 自身会移动,指向 master。如下图所示:

所以,虽然在这两种情况下我们都移动 HEAD 使其指向了提交 A,但是方式是不同的。 reset 会移动 HEAD 分支的指向,而 checkout 则移动 HEAD 自身。

2、命令后面接文件名的情况

命令后面接文件或者目录名称的时候,执行 checkout 的效果和 reset 一样,不会移动 HEADgit checkout [branch] file 等同 git reset --hard [branch] file,不仅会用某次提交中的那个文件来更新索引,同时也会覆盖工作目录中对应的文件(这样对工作目录并不安全)!

注:这里的 [branch] 可以是分支名称,也可以是 commit 或者是 HEAD 一类的符号引用。本质上,它们最终都定位到某个提交。

留下评论