git工具-6-checkout
检出与重置的区别
和 reset 一样,checkout 也操纵三棵树,不过它有一点不同,这取决于你是否传给该命令一个文件路径。
不带路径检出
运行 git checkout [branch] 与运行 git reset --hard [branch] 非常相似,它会更新所有三棵树使其看起来像 [branch],不过有两点重要的区别:
-
首先不同于
reset --hard,checkout对工作目录是安全的,它会通过检查来确保不会将已更改的文件吹走。 其实它还更聪明一些。它会在工作目录中先试着简单合并一下,这样所有_还未修改过的_文件都会被更新。 而reset --hard则会不做检查就全面地替换所有东西。 -
第二个重要的区别是如何更新
HEAD。reset会移动HEAD分支的指向,而checkout只会移动HEAD自身来指向另一个分支。
例如,假设我们有 master 和 develop 分支,它们分别指向不同的提交;我们现在在 develop 上(所以 HEAD 指向它)。
1 | $ git log --all --oneline --graph |
如果我们运行 git reset master,那么 develop 自身现在会和 master 指向同一个提交:
1 | MINGW64 /d/tmp/git-playground1 (develop) |
而如果我们运行 git checkout master 的话,develop 不会移动,HEAD 自身会移动。 现在 HEAD 将会指向 master:
1 | MINGW64 /d/tmp/git-playground2 (develop) # develop分支 |
所以,虽然在这两种情况下我们都移动 HEAD 使其指向了提交 A,但_做法_是非常不同的。 reset 会移动 HEAD 分支的指向(比如上面的develop指针),而 checkout 则移动 HEAD 自身,不移动develop指针。
带路径检出
运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD。
它就像 git reset [branch] file 那样用该次提交中的那个文件来更新索引(Index),但是它也会覆盖工作目录中对应的文件。 它就像是 git reset --hard [branch] file(如果 reset 允许你这样运行的话)- 这样对工作目录并不安全,它也不会移动 HEAD。
此外,同 git reset 和 git add 一样,checkout 也接受一个 --patch 选项,允许你根据选择一块一块地恢复文件内容。
总结
希望你现在熟悉并理解了 reset 命令,不过关于它和 checkout 之间的区别,你可能还是会有点困惑,毕竟不太可能记住不同调用的所有规则。
下面的速查表列出了命令对树的影响。 “HEAD” 一列中的 “REF” 表示该命令移动了 HEAD 指向的分支引用,而HEAD 则表示只移动了 HEAD 自身。 特别注意 WD Safe? 一列 - 如果它标记为 NO,那么运行该命令之前请考虑一下。
| HEAD | Index | Workdir | WD Safe? | |
|---|---|---|---|---|
| Commit Level | ||||
reset --soft [commit] |
REF | NO | NO | YES |
reset [commit] |
YES | |||
reset --hard [commit] |
YES | NO | ||
checkout [commit] |
HEAD | YES | ||
| File Level | ||||
reset (commit) [file] |
NO | YES | NO | YES |
checkout (commit) [file] |
YES | NO | ||





