Git 上的插图(Jon Loeliger)很好地描述了HEAD^和HEAD~之间的关系
对于初学者来说,本文档可能有点晦涩难懂,因此我复制了下面的说明:Git 上的插图(Jon Loeliger)很好地描述了HEAD^和HEAD~之间的关系,git,Git,对于初学者来说,本文档可能有点晦涩难懂,因此我复制了下面的说明: G H I J \ / \ / D E F \ | / \ \ | / | \|/ | B C \ / \ / A A = = A^0 B = A^ = A^1 = A~1 C = A^2 D = A^^ = A^1^1 = A~2 E = B^2 = A^^
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
值得注意的是,git还有一个跟踪“从哪里来”/“现在想回去”的语法,例如,
HEAD@{1}
将引用您跳转到新提交位置的位置
基本上,HEAD@{}
变量捕获头部运动的历史,您可以通过使用命令git reflog
查看git的reflogs来决定使用特定头部
例如:
0aee51f HEAD@{0}: reset: moving to HEAD@{5}
290e035 HEAD@{1}: reset: moving to HEAD@{7}
0aee51f HEAD@{2}: reset: moving to HEAD@{3}
290e035 HEAD@{3}: reset: moving to HEAD@{3}
9e77426 HEAD@{4}: reset: moving to HEAD@{3}
290e035 HEAD@{5}: reset: moving to HEAD@{3}
0aee51f HEAD@{6}: reset: moving to HEAD@{3}
290e035 HEAD@{7}: reset: moving to HEAD@{3}
9e77426 HEAD@{8}: reset: moving to HEAD@{3}
290e035 HEAD@{9}: reset: moving to HEAD@{1}
0aee51f HEAD@{10}: reset: moving to HEAD@{4}
290e035 HEAD@{11}: reset: moving to HEAD^
9e77426 HEAD@{12}: reset: moving to HEAD^
eb48179 HEAD@{13}: reset: moving to HEAD~
f916d93 HEAD@{14}: reset: moving to HEAD~
0aee51f HEAD@{15}: reset: moving to HEAD@{5}
f19fd9b HEAD@{16}: reset: moving to HEAD~1
290e035 HEAD@{17}: reset: moving to HEAD~2
eb48179 HEAD@{18}: reset: moving to HEAD~2
0aee51f HEAD@{19}: reset: moving to HEAD@{5}
eb48179 HEAD@{20}: reset: moving to HEAD~2
0aee51f HEAD@{21}: reset: moving to HEAD@{1}
f916d93 HEAD@{22}: reset: moving to HEAD@{1}
0aee51f HEAD@{23}: reset: moving to HEAD@{1}
f916d93 HEAD@{24}: reset: moving to HEAD^
0aee51f HEAD@{25}: commit (amend): 3rd commmit
35a7332 HEAD@{26}: checkout: moving from temp2_new_br to temp2_new_br
35a7332 HEAD@{27}: commit (amend): 3rd commmit
72c0be8 HEAD@{28}: commit (amend): 3rd commmit
一个例子可能是,我做了本地提交a->b->c->d,然后我放弃了2次提交来检查我的代码-
git reset HEAD~2
,然后我想把我的头移回d-git reset HEAD@{1}
和^
都是指提交的父项(~~
和^
都指祖父母提交等),但它们与数字一起使用时含义不同:
~2
表示如果提交有多个父级,则通过第一个父级在层次结构中向上提升两级
^2
表示第二个父级,其中提交有多个父级(即,因为它是合并)
这些可以组合在一起,因此HEAD~2^3
意味着HEAD的祖父母提交的第三个父母提交的。我的两分钱
这里有一个很好的解释,逐字逐句地从以下几个方面进行解释:
ref~
是ref~1
的缩写,表示提交的第一个父级。ref~2
表示提交的第一个父级。ref~3
表示提交的第一个父级的第一个父级。依此类推
ref^
是ref^1
的缩写,表示提交的第一个父级。但两者的不同之处在于ref^2
表示提交的第二个父级(请记住,提交在合并时可以有两个父级)
可以组合使用^
和~
运算符
简单地说:
~
指定祖先
^
指定父项
合并时可以指定一个或多个分支。然后提交有两个或多个父级,然后^
用于指示父级
假设您在分支A上,您还有两个分支:B和C
在每个分支上,最后三次提交是:
- A:A1、A2、A3
- B:B1、B2、B3
- C:C1、C3、C3
如果现在在分支A上执行命令:
git merge B C
然后将三个分支组合在一起(这里,合并提交有三个父级)
及
~
表示第一个分支中的第n个祖先,因此
头部~
表示A3
HEAD~2
表示A2
头3
表示A1
^
表示第n个父项,因此
HEAD^
表示A3
头^2
表示B3
头^3
表示C3
相邻的~
或^
的下一次使用是在前面字符指定的提交上下文中
注意1:
HEAD~3
始终等于:HEAD~~~
和to:HEAD^^^
(每个表示A1)
和一般情况下:
HEAD~n
始终等于:HEAD~…
(n次~
)和to:HEAD^ ^ ^
(n次^
)
注意2:
HEAD^3
与HEAD^^^
不同(第一个表示C3,第二个表示A1)
和一般情况下:
HEAD^1
与HEAD^
相同
- 但是对于n>1:
HEAD^n
总是而不是HEAD^…^
(n次~
)
简单地说,对于第一级亲子关系(祖先、继承、世系等),HEAD^和HEAD~都指向同一个提交,即(位于)头部上方的一个父级(提交)
此外,HEAD^=HEAD^1=HEAD~=HEAD~1。但是HEAD^^!=HEAD^2!=HEAD~2。但是HEAD^^=HEAD~2。请继续阅读
在第一级亲子关系之外,事情变得更加棘手,特别是如果工作分支/主分支(从其他分支)进行了合并的话。还有插入符号的语法问题,HEAD^^^=HEAD~2(它们是等效的),但HEAD^^!=HEAD^2(它们完全是两个不同的东西)
每个/每个插入符号都指头部的第一个父级,这就是为什么将插入符号串在一起相当于波浪形表达式,因为它们指的是第一个父级(第一个父级)的第一个父级等,严格基于连接的插入符号上的数字或波浪形后面的数字(无论哪种方式,它们都表示相同的事情),也就是说,与第一代父母同住,然后再上x代
HEAD~2(或HEAD^^^)指的是在层次结构中当前提交(HEAD)之上/之上的两个祖先级别的提交,即HEAD的祖父母提交
另一方面,头^2不是指第一个父项的第二个父项的提交,而是指第二个父项的提交。这是因为插入符号表示提交的父项,下面的数字表示提交的父项(如果插入符号后面没有数字,则指第一个父项)[因为它是数字为1的简写,意味着第一个父项]。与插入符号不同,后面的数字并不意味着上一级的层次结构
$ git log -1 --format=%f $(git rev-parse A^)
B
$ git log -1 --format=%f $(git rev-parse A~^3~)
I
$ git log -1 --format=%f $(git rev-parse A^2~)
F
commit 89e4fcb0dd01b42e82b8f27f9a575111a26844df
Merge: c670b1f876 649bf3a42f b67d40adbb
Author: Junio C Hamano <gitster@pobox.com>
Date: Mon Oct 29 10:15:31 2018 +0900
Merge branches 'bp/reset-quiet' and 'js/mingw-http-ssl' into nd/config-split […]
$ git rev-parse 89e4fcb0dd^1 89e4fcb0dd^2 89e4fcb0dd^3
c670b1f876521c9f7cd40184bf7ed05aad843433
649bf3a42f344e71b1b5a7f562576f911a1f7423
b67d40adbbaf4f5c4898001bf062a9fd67e43368
$ git rev-parse 89e4fcb0dd^4
89e4fcb0dd^4
fatal: ambiguous argument '89e4fcb0dd^4': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ git log -1 --pretty=%P 89e4fcb0dd
c670b1f876521c9f7cd40184bf7ed05aad843433 649bf3a42f344e71b1b5a7f562576f911a1f7423 b67d40adbbaf4f5c4898001bf062a9fd67e43368
$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
0aee51f HEAD@{0}: reset: moving to HEAD@{5}
290e035 HEAD@{1}: reset: moving to HEAD@{7}
0aee51f HEAD@{2}: reset: moving to HEAD@{3}
290e035 HEAD@{3}: reset: moving to HEAD@{3}
9e77426 HEAD@{4}: reset: moving to HEAD@{3}
290e035 HEAD@{5}: reset: moving to HEAD@{3}
0aee51f HEAD@{6}: reset: moving to HEAD@{3}
290e035 HEAD@{7}: reset: moving to HEAD@{3}
9e77426 HEAD@{8}: reset: moving to HEAD@{3}
290e035 HEAD@{9}: reset: moving to HEAD@{1}
0aee51f HEAD@{10}: reset: moving to HEAD@{4}
290e035 HEAD@{11}: reset: moving to HEAD^
9e77426 HEAD@{12}: reset: moving to HEAD^
eb48179 HEAD@{13}: reset: moving to HEAD~
f916d93 HEAD@{14}: reset: moving to HEAD~
0aee51f HEAD@{15}: reset: moving to HEAD@{5}
f19fd9b HEAD@{16}: reset: moving to HEAD~1
290e035 HEAD@{17}: reset: moving to HEAD~2
eb48179 HEAD@{18}: reset: moving to HEAD~2
0aee51f HEAD@{19}: reset: moving to HEAD@{5}
eb48179 HEAD@{20}: reset: moving to HEAD~2
0aee51f HEAD@{21}: reset: moving to HEAD@{1}
f916d93 HEAD@{22}: reset: moving to HEAD@{1}
0aee51f HEAD@{23}: reset: moving to HEAD@{1}
f916d93 HEAD@{24}: reset: moving to HEAD^
0aee51f HEAD@{25}: commit (amend): 3rd commmit
35a7332 HEAD@{26}: checkout: moving from temp2_new_br to temp2_new_br
35a7332 HEAD@{27}: commit (amend): 3rd commmit
72c0be8 HEAD@{28}: commit (amend): 3rd commmit
git merge B C