概念
在git
中有一个特殊的符号引用:HEAD
,我们可以成它为头指针。HEAD
是一个对当前检出记录的符号引用 ------ 也就是指向你正在其基础上进行工作的提交记录。
HEAD
总是指向当前分支上最近一次提交记录。大多数修改提交树的git
命令都是从改变 HEAD
的指向开始的。
HEAD
通常情况下是指向分支名的(如 bugFix
)。在你提交时,改变了 bugFix
的状态,这一变化通过 HEAD
变得可见。
注:如果想看 HEAD 指向,可以通过
cat .git/HEAD
查看, 如果 HEAD 指向的是一个引用,还可以用git symbolic-ref HEAD
查看它的指向
图示
我们来通过图示看一下头指针分离究竟是这样的。
我们使用一下命令可使头指针分离
bash
# checkout时不指定具体的分支名,而是指定某一次提交的哈希,如上图的C1
git checkout C1
从上图我们可以看到两个主要的变化:
-
main
分支上的*
不见了,也就是我们当前的代码版本应不是指向main
分支了 -
多了一个
HEAD
指针指向C1
这个哈希对应的提交记录。
这就是所谓的头指针分离,通常我们的HEAD
指针是执行某一个分支名的,如当HEAD
指向了main
分支是,main
分支就会带上*
,而通过上述操作,便将头指针与具体的分支名分离了。
头指针分离的常见用途
-
当我们修改了一堆代码之后,想要回去之前的某一些提交,看看之前的代码是如何实现的,此时,我们就可以使用头指针分离,检出目标提交的代码查看,查看完之后再切回原本的分支继续开发即可
-
做一些不太确定的尝试工作时,我们可以先基于某一次提交分离头指针出来进行尝试修改,如果最终方案可行,再把代码放到目标分支提交。
相对引用
上面我们都是通过提交记录的哈希值在git中移动指针的,实际工作过程中你不得不使用git log
查看目标提交记录的哈希值,并且哈希值在真实的 Git 世界中也会更长(基于 SHA-1,共 40 位)。例如fed2da64c0efc5293610bdd892f82a58e8cbc5d8
。但令人欣慰的是,Git 对哈希的处理很智能。你只需要提供能够唯一标识提交记录的前几个字符即可。因此我可以仅输入fed2
而不是上面的一长串字符。
但是,如果我们使用相对引用的话,让指针在git上移动起来就更加方便了。
使用相对引用的话,你就可以从一个易于记忆的地方(比如 bugFix
分支或 HEAD
)开始计算。
相对引用非常给力,这里我介绍两个简单的用法:
- 使用
^
向上移动 1 个提交记录 - 使用
~<num>
向上移动多个提交记录,如~3
例如下面的图:
我们想让头指针移动到C1
所在的位置
bash
# 方法一:直接用哈希值切换
git checkout C1
# 方法二:使用相对引用
git checkout HEAD^
上面两个命令都可以达到这个效果。那么,有同学可能会问了,感觉还是哈希值简单一点呀。我们不要忘了,这边哈希值C1
是我们为了画图简化的,真实的哈希值异常复杂。我们再来看看下面这个:
如果想要将头指针依次移动到C2
、C1
、C0
呢?
bash
# 方法一:哈希值
git checkout C2
git checkout C1
git checkout C0
# 方法二:相对引用
git checkout HEAD^
git checkout HEAD^
git checkout HEAD^
现在是否觉得,相对引用更简单了呢?
可能还有写同学觉得,者还是要使用三次HEAD^
才能到达目标点,有没有一次到达的方法呢?当然有
如果你想在提交树中向上移动很多步的话,敲那么多 ^
貌似也挺烦人的,Git 当然也考虑到了这一点,于是又引入了操作符 ~
。
该操作符后面可以跟一个数字(可选,不跟数字时与 ^
相同,向上移动一次),指定向上移动多少次。
还是上面的示例:
bash
git checkout HEAD~3
这样也可以达到头指针移动到当前分支之前3个版本的位置。
我使用相对引用最多的就是移动分支。可以直接使用 -f
选项让分支指向另一个提交。例如:
git branch -f main HEAD~3
上面的命令会将 main 分支强制指向 HEAD 的第 3 级父提交。
这样,我们就已经将main
分支强制移动到了原来位置的第三级父节点处了。