Git HEAD 重置和分离头指针

2019-04-03 0 By admin

一、HEAD的重置即检出

HEAD可以理解为“头指针”,是当前工作区的“基础版本”,当执行提交时,HEAD指向的提交将作为新提交的父提交。
1、看看当前HEAD的指向。
$ cat .git/HEAD
ref: refs/heads/master

可以看出HEAD指向了分支 master。
2、此时执行git branch会看到当前处于master分支。
$ git branch -v
* master 4902dc3 does master follow this new commit?

3、现在使用git checkout命令检出该ID的父提交,看看会怎样。
$ git checkout 4902dc3^
Note: checking out '4902dc3^'.
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
HEAD is now at e695606... which version checked in?

翻译一下:
注意: 正检出 '4902dc3^'.
您现在处于 '分离头指针' 状态。您可以检查、测试和提交,而不影响任何分支。
通过执行另外的一个 checkout 检出指令会丢弃在此状态下的修改和提交。
如果想保留在此状态下的修改和提交,使用 -b 参数调用 checkout 检出指令以
创建新的跟踪分支。如:
git checkout -b new_branch_name
头指针现在指向 e695606... 提交说明为: which version checked in?

二、分离头指针

1、查看一下此时HEAD的内容就明白了。
$ cat .git/HEAD
e695606fc5e31b2ff9038a48a3d363f4c21a3d86

原来“分离头指针”状态指的就是HEAD头指针指向了一个具体的提交ID,而不是一个引用(分支)。
2、查看最新提交的reflog也可以看到当针对提交执行git checkout命令时,HEAD头指针被更改了:由指向master分支变成了指向一个提交ID。
$ git reflog -1
e695606 HEAD@{0}: checkout: moving from master to 4902dc3^

注意上面的reflog是HEAD头指针的变迁记录,而非master分支。
3、查看一下HEAD和master对应的提交ID,会发现现在它们指向的不一样。
$ git rev-parse HEAD master
e695606fc5e31b2ff9038a48a3d363f4c21a3d86
4902dc375672fbf52a226e0354100b75d4fe31e3

前一个是HEAD头指针的指向,后一个是master分支的指向。
而且还可以看到执行git checkout命令并不像git reset命令,分支(master)的指向并没有改变,仍旧指向原有的提交ID。

三、在分离头指针上进行提交

1、先做一次修改:创建一个新文件detached-commit.txt,添加到暂存区中。
$ touch detached-commit.txt
$ git add detached-commit.txt

2、执行提交。在提交输出中也会出现[detached HEAD …]的标识,也是对用户的警示。
$ git commit -m "commit in detached HEAD mode."
[detached HEAD acc2f69] commit in detached HEAD mode.
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 detached-commit.txt

3、此时头指针指向了新的提交。
$ cat .git/HEAD
acc2f69cf6f0ae346732382c819080df75bb2191

4、返回到master分支中
$ git checkout master
Previous HEAD position was acc2f69... commit in detached HEAD mode.
Switched to branch 'master'

返回master分支后,之前在分离头模式提交的修改我们是看不到的。
5、切换之后,刚才的提交日志也不见了。
$ git log --graph --pretty=oneline
6、我们可以使用show命令通过commit id 查看在分离头指针状态下的提交。
$ git show acc2f69
commit acc2f69cf6f0ae346732382c819080df75bb2191
Author: Jiang Xin
Date: Sun Dec 5 15:43:24 2010 +0800
commit in detached HEAD mode.
diff --git a/detached-commit.txt b/detached-commit.txt
new file mode 100644
index 0000000..e69de29

可以看出这个提交现在仍在版本库中。由于这个提交没有被任何分支跟踪到,因此并不能保证这个提交会永久存在。
实际上当reflog中含有该提交的日志过期后,这个提交随时都会从版本库中彻底清除。

四、挽救分离头指针

在“分离头指针”模式下进行的测试提交除了使用提交ID(acc2f69)访问之外,不能通过master分支或其他引用访问到。
如果这个提交是master分支所需要的,那么该如何处理呢?
如果使用git reset命令,的确可以将master分支重置到该测试提交acc2f69,但是如果那样就会丢掉master分支原先的提交4902dc3。
使用合并操作(git merge)可以实现两者的兼顾。
1、下面的操作会将提交acc2f69合并到master分支中来。执行合并操作,将acc2f69提交合并到当前分支。
$ git merge acc2f69
Merge made by recursive.
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 detached-commit.txt

工作区中多了一个detached-commit.txt文件;新的提交会有两个父提交,这就是合并的奥秘。