获取git某分支的祖先提交(HEAD^2和HEAD~2)

2,805 阅读2分钟

在回滚等一些git操作时,常会出现获取祖先提交来定位回滚位置,比如本地工作区代码回滚到上一次提交:

git reset --hard HEAD~

此处的HEAD~就是指当前所在分支的上一次提交,除了~之外,还有一个^也是用于查找祖先提交。

~ 的作用

<rev>~<n> 用来表示一个提交的第 n 个祖先提交,如果不指定 n,那么默认为 1。

比如,想要获取 HEAD 的第 5 个祖先提交,可以用 HEAD~5 就表示。

注意,HEAD~~HEAD~2 是等价的,HEAD~0HEAD等价的。

如下,C为从A提交处再产生了2次提交,因此AC~2是等价的

C
|
B
|
A

^的作用

<rev>^<n> 用来表示一个提交的第 n 个父提交,如果不指定 n,那么默认为 1。

比如,在一个提交引用C是由B合并到A中并产生的一个新提交

C
|\
A B

此时认为A是C的第一个父祖先提交,B是C的第二个父祖先提交,因此通过提交引用C来获取B的表达式为:C^2

注意:HEAD^^^ 并不等价于 HEAD^3,而是等价与 HEAD^1^1^1

两者关系

~ 获取第一个祖先提交,^ 可以获取第一个父提交。 其实第一个祖先提交就是第一个父提交,反之亦然。 因此,当 n 为 1 时,~ 和 ^ 其实是等价的。 譬如:HEAD~~~ 和 HEAD^^^ 是等价的。

案例说明

下面基于某个仓库的提交记录进行说明,此说明需要两个git命令进行辅助说明。

  1. 在命令行中可视化各个提交节点的关系

    git log --graph --oneline
    
  2. 查看某个分支指向哪个特定的 SHA-1

    git rev-parse <branch>
    

基于某个仓库可视化查看各提交之间的关系如下图:

*   a38629f (HEAD -> master) L Merge branch 'J'
|\  
| *   8951b50 (J) J `Merge branch 'G' into J
| |\  
| | *   abbe463 (G) G Merge branch 'C' into G
| | |\  
| | | * ecc718a (C) C
* | | |   6577476 K Merge branch 'F'
|\ \ \ \  
| * | | | b40f2da (F) I
| |/ / /  
| * / / 57bc38a F
| |/ /  
* | | ad26a1b H
* | | 895e64d E
|/ /  
* / 198a934 B
|/  
* e2cc0b5 A

摊平根据其提交信息(上图括号内表示分支)画出下图:

L
|\
K \
|\  \
| \  \
H   I  J   
|   | / |  
E   F   G
 \  |  / \
  \ | /  |
   \|/   | 
    B    C
     \  /
      \/
	  A

因此K可以用其第4个祖先提交表示A(K-H-E-B-A),也就是K~4

$ git rev-parse 6577476~4
# 结果输出
e2cc0b5997ed87efb49c88a779d9e9c648640fca

也可以是用其第2个父提交的第3个祖先提交来表示(K-I-F-B-A),K^2~3

$ git rev-parse 6577476^2~3
# 结果输出
e2cc0b5997ed87efb49c88a779d9e9c648640fca

再比如说,G是由C合并B所得到,所以B是G的第一个父提交,而C是第2个父提交,因此以下两个命令都可以获取到A提交e2cc0b5997ed87efb49c88a779d9e9c648640fca

$ git rev-parse abbe463~2
$ git rev-parse abbe463^2~1