第8章 Git 检出
#52 · open · 8 comments
View on GitHub ↗
**`HEAD`的重置即检出**
在在上一章我们学习了重置命令(`gitreset`)。重置命令的一个用途就是修改引用(如`master`)的游标指向。实际上在执行重置命令的时候没有使用任何参数对所要重置的分支名(如`master`)进行设置,这是因为重置命令实际上所针对的是头指针`HEAD`。之所以重置命令没有改变头指针`HEAD`的内容,是因为`HEAD`指向了一个引用`res/heads/master`,所以重置命令体现为分支“游标”的变更,`HEAD`本身一直指向的是`refs/heads/master`,并没有在重置时改变。
如果`HEAD`的内容不能改变而一直都指向`master`分支,那么Git如此精妙的分支设计岂不是浪费?如果`HEAD`要改变该如何改变呢?本章将学习检出命令(`gitcheckout`),该命令的实质就是修改`HEAD`本身的指向,该命令不会影响分支“游标”(如`master`)。
Comments
**挽救分离头指针**
在“分离头指针”模式下进行的测试提交除了使用提交ID(acc2f69)访问之外,不能 通过 master分支或其他引用访问到。如果这个提交是 master分支所需要的,那么该如何处 理呢?如果使用上一章介绍的 `git reset`命令,的确可以将 master分支重置到该测试提交 “ac2f69”,但是如果那样就会丢掉 master分支原先的提交“4902dc3”。使用合并操作(`git merge`)可以实现两者的兼顾。
**深入了解 `git checkout`命令**
检出命令(`git checkout`)是Git最常用的命令之一,同时也是一个很危险的命令, 因为这条命令会重写工作区。检出命令的用法如下:
用法一:`git checkout [-q] [<commit>] [--] <paths>`
用法二:`git checkout [<branch>]`
用法三:`git checkout [-m] [[-b | --orphan] <new branch>] [<start_point>]`
上面列出的第一种用法和第二种用法的区别在于,第一种用法在命令中包含路径 `< paths>`。为了避免路径和引用(或者提交ID)同名而发生冲突,可以在 `<paths>`前用两个连续的短线(减号)作为分隔。
第一种用法的`<commit>`是可选项,如果省略则相当于从暂存区(`index`)进行检出。这和上一章的重置命令大不相同:重置的默认值是`HEAD`,而检出的默认值是暂存区。因此重置一般用于重置暂存区(除非使用`--hard`参数,否则不重置工作区),而检出命令主要是覆盖工作区(如果`<commit>`不省略,也会替换暂存区中相应的文件)。
第一种用法(包含了路径`<paths>的用法)不会改变HEAD头指针,主要是用于指定版本的文件覆盖工作区中对应的文件。如果省略<commit>,则会用暂存区的文件覆盖工作区的文件,否则用指定提交中的文件覆盖暂存区和工作区中对应的文件
第二种用法(不使用路径<paths>的用法)则会改变HEAD头指针。之所以后面的参数写作<branch>,是因为只有HEAD切换到一个分支才可以对提交进行跟踪,否则仍然会进入“分离头指针”的状态。在“分离头指针”状态下的提交不能被引用关联到,从而可能丟失。所以用法二最主要的作用就是切换到分支。如果省略<branch>则相当于对工作区进行状态检查。
第三种用法主要是创建和切换到新的分支(<new branch>,新的分支从<start point>指定的提交开始创建。新分支和我们熟悉的 master分支没有什么实质的不同,都是在`refs/heads`命名空间下的引用。关于分支和 `git checkout`命令的这个用法会在后面的章节具体介绍。

命令:`git checkout branch`
检出 branch分支。要完成如图8-1中的三个步骤,更新HEAD以指向 branch分支, 以及用 branch指向的树更新暂存区和工作区。
命令:`git checkout`
汇总显示工作区、暂存区与HEAD的差异。
命令:`git checkout filename`
用暂存区中`filename`文件来覆盖工作区中的`filename`文件。相当于取消自上次执行 `git add filename`以来(如果执行过)的本地修改。
这个命令很危险,因为对于本地的修改会悄无声息地覆盖,毫不留情。
命令:`git checkout branch filename`
维持HEAD的指向不变。用 branch所指向的提交中的 filename替换暂存区和工作区中相应的文件。注意会将暂存区和工作区中的 filename文件直接覆盖。
命令:`git checkout --` 或写作 `git checkout .`
注意 `git checkout`命令后的参数为一个点(`.`)。这条命令最危险!会取消所有本地 的修改(相对于暂存区)。相当于用暂存区的所有文件直接覆盖本地文件,不给用户任何 确认的机会!