【git】checkout时遇到的detached HEAD问题
checkout
checkout本质改变的是head指向,将进行以下步骤:
- 将HEAD指向那个分支的最后一次commit
- 将HEAD指向的commit里所有文件的snapshot替换掉Index区域里原来的内容
- 将Index区域里的内容填充到Working Directory里
checkout一般有3个用法:
git checkout [<commit id>] [--] <paths>
也是这次出现错误的命令。该命令主要用于用于拿暂存区的文件覆盖工作区的文件,或者用指定提交中的文件覆盖暂存区和工作区中对应的文件。如果不填写commit id,则默认会从暂存区检出该文件,如果暂存区为空,则该文件会回滚到最近一次的提交状态。
checkout <branch>
切换分支。
git checkout -b <new_branch> [<start_point>]
分支的创建和切换。指定的 [<start_point>]
是新分支的指向,否则指向当前HEAD。
※ checkout不带文件参数时与 reset --hard的区别:
1. reset把branch移动到HEAD指定的地方,而checkout则把HEAD移动到另一个分支。
2. reset有可能会把working directory里未提交内容都更新掉(分支指针改变,工作区未提交的文件被覆盖,
同时丢弃某个提交之后的所有提交!!!),而checkout不会去修改你在Working Directory里未提交过
的文件,原因在于未提交不能切换分支,而提交后将被保留在某次commit中不会丢失,可以切回。
HEAD
正常情况下,HEAD指向一个branch,而branch又指向一个commit。
重要的一点是:HEAD只能指向本地的某个commit或者本地分支,当git checkout 远程分支
,而本地又没有这个分支,此时HEAD指向commit就会进入detached HEAD state。
detached HEAD
detached HEAD state指的是HEAD指针没有指向任何的branch,而是指向了一个commit。进入 detached HEAD 状态后 git 会创建一个临时分支,但默认不保存。
现在的提交commit链在git checkout这个commit的基础上展开,但是如果直接离开到一个branch上的话,这些commits就会被当成garbage,被git garbage collection routine所回收。
但是,我们也可以保留这些commits,有下面三种方式:
$ git checkout -b foo
创建一个branch指向这个commit链,然后HEAD指向这个branch,于是HEAD就不是处于detached state。
$ git branch foo
创建一个branch指向这个commit链,但是HEAD还是处于detached state。
$ git tag foo
创建一个tag指向这个commit链,HEAD还是处于detached state。