Git中HEAD ^和HEAD~之间有什么区别?

TK.*_*TK. 688 git

当我在Git中指定一个祖先提交对象时,我在HEAD^和之间感到困惑HEAD~.

两者都有像" HEAD^3和"这样的"编号"版本HEAD~2.

它们看起来与我非常相似或相同,但是波浪号和插入符之间有什么区别吗?

Gre*_*con 663

~ 表示当前分支的提示的第一个父级.

请记住,git提交可以有多个父级.^是的缩写~,你也可以^适当地解决等问题.

你可以找到任何提交的父母,而不仅仅是git rev-parse.您也可以追溯到几代人:例如,~意味着主分支的祖父母,在歧义的情况下支持第一个父母.这些说明符可以被任意连接,例如,<rev>~<n>.

有关完整的详细信息,请参阅文档中的"指定修订"master~3.

为了有一个想法的直观表示,让我们引用文档的一部分:

以下是Jon Loeliger的插图.提交节点B和C都是提交节点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
Run Code Online (Sandbox Code Playgroud)

  • @duckx图表实际上是从上到下,所以A是最近的提交,而G是最老的之一.从我所知道的,从G到D的路径是向前的,而不是向后的. (11认同)
  • 如果上面的内容有点难以理解(对我来说),那么这篇文章就更容易理解了:https://salferrarello.com/git-head-tilde-vs-head-caret/ (3认同)
  • @SimonBudin 我猜,用`^^^^^^^` 代替`~7` 不是很方便,是吗?这就是为什么 `~` 很有用 (2认同)

g_f*_*red 331

http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html上找到的插图(作者Jon Loeliger)很好地描述了HEAD^和之间的区别.HEAD~

这个文档对初学者来说有点模糊,所以我再现了下面的插图:

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
Run Code Online (Sandbox Code Playgroud)

  • 只有一个问题.承诺如何拥有两个以上的父母?(参见B - 它的父母是D,E和F)我认为提交可以拥有两个父母的唯一方法是它是一个合并提交...但是你怎么能同时合并3个提交? (10认同)
  • @tsikov @Julian A。或者在这个例子中,有人在分支 D 上,并运行“git merge EF”。最终的提交是 B. (6认同)
  • 所以,`^ == ^1 == LEFTMOST PARENT`,`^2 == SECOND LEFTMOST PARENT` 等等。并且`~ == ~1 == LEFTMOST PARENT`,`~2 == LEFTMOST PARENTS LEFTMOST PARENT == LEFTMOST GRANDPARENT`。通过扩展,`~2^2 == 左祖父母第二个左父母` (4认同)
  • @tsikov 如果你在分支 A,你可以执行 `git merge BC`。这是一个三路合并。 (3认同)
  • 另外,`F = A ^ 2 ^`. (2认同)
  • @AlexanderTorstling 这对我很有帮助。但是,这里的左和右是什么意思? (2认同)
  • Git 如何知道 B = A^1 且 C = A^2,而不是相反。对我来说, B 和 C 看起来没有区别,因为我们对它们的了解就是它们被合并以创建 A 。也就是说,为什么我们不应该假设 B = A^2 和 C = A^1 ?据我所知,该图本身并没有给出任何假设的真正理由。 (2认同)
  • 我现在明白为什么了。[原始来源](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-rev-parse.html)中有一个关键事实:*父提交按左顺序排列-向右。*。这可能应该包含在答案中。 (2认同)

Mat*_*dge 273

双方~^就自己参考的提交父(~~^^两个指祖父母提交,等等),但他们在不同的含义时,他们用数字使用:

  • ~2装置向上层次结构中的两个电平,经由如果提交具有多于一个亲本的第一个父

  • ^2表示提交具有多个父项的第二个父项(即因为它是合并)

这些可以组合,所以HEAD~2^3意味着HEAD祖父母提交的第三个父提交.

  • 这应该是公认的答案,比其他答案简洁明了. (21认同)
  • 这个答案使我区分了无数字和有数字的插入号/波浪号!我以为`^^`与`^ 2`相同,但不是。 (3认同)
  • `branch^` 和 `branch~` 是同一个东西。在这一点上做得很好 - 我来到这里想知道是否输入“git reset HEAD^”或“git reset HEAD~”。如果我先读到这个答案,我可能会早点离开。 (3认同)
  • 读完这本书之后,再从http://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git/12527561#12527561中读取图片,这是很合理的。 (2认同)

Ale*_*zik 268

我的两分钱......

在此输入图像描述

  • 如果我猜对了,提交`A`、`B`、`D`、`G`在同一个分支上,提交`D`是`G`和`H`的合并,因此有两个父母。所以来自其他分支的提交(`H`)被`^2`引用。 (4认同)
  • 箭头“~2”相对于提交“A”,而不是“B”,因此它应该从“A”开始,而不是“B”。 (3认同)

dr0*_*r01 53

这是http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde逐字记录的非常好的解释:

ref~是简历ref~1,表示提交的第一个父级.ref~2表示提交的第一个父亲的第一个父亲.ref~3表示提交的第一个父级的第一个父级的第一个父级.等等.

ref^是简历ref^1,表示提交的第一个父级.但是两者的不同之处在于它ref^2意味着提交的第二个父级(请记住,提交在合并时可以有两个父级).

^~运营商可以进行组合.

在此输入图像描述

  • 感谢您实际解释差异,而不是发布大量示例。 (5认同)

jam*_*san 31

^<n>格式允许您选择提交的第n个父级(在合并中相关).该~<n>格式允许您选择第n个祖先提交,始终跟随第一个父级.有关示例,请参阅git-rev-parse的文档.


ash*_*ish 19

值得注意的是,git还具有跟踪"从哪里来"或"现在想回去"的语法 - 例如,HEAD@{1}将引用您跳转到新提交位置的位置.

基本上HEAD@{}变量捕获HEAD运动的历史,你可以通过使用命令查看git的reflog来决定使用特定的头git reflog.

例:

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
Run Code Online (Sandbox Code Playgroud)

一个例子可能是我做了local-commit a-> b-> c-> d然后我回去丢弃2次提交来检查我的代码 - git reset HEAD~2然后我想把我的HEAD移回d - git reset HEAD@{1}.


sim*_*eco 15

简单地说:

  • ~ 指定祖先
  • ^ 指定父母

您可以在合并时指定一个或多个分支.然后一个提交有两个或更多的父母,然后^有助于表明父母.

假设你是在分支一个和你有两个分支:Ç.

在每个分支上,最后三个提交是:

  • :A1,A2,A3
  • B:B1,B2,B3
  • C:C1,C3,C3

如果现在在分支A上执行命令:

git merge B C
Run Code Online (Sandbox Code Playgroud)

然后你将三个分支组合在一起(这里你的合并提交有三个父母)

~ 表示第一个分支中的第n个祖先,所以

  • HEAD~表示A3
  • HEAD~2表示A2
  • HEAD~3表示A1

^ 表示第n个父母,所以

  • HEAD^表示A3
  • HEAD^2表示B3
  • HEAD^3表示C3

下一个使用~^彼此相邻的是在前一个字符指定的提交的上下文中.

通知1:

  • HEAD~3总是等于:HEAD~~~和:( HEAD^^^每个表示A1),

        一般来说:

  • HEAD~n总是等于:HEAD~...~(Ñ~)和:HEAD^...^(Ñ^).

通知2:

  • HEAD^3一样的HEAD^^^(第一个表示C3,第二个表示A1),

        一般来说:

  • HEAD^1是一样的HEAD^,
  • 但是对于n > 1:HEAD^n总是与(n次)一样.HEAD^...^~


Ale*_*ler 12

OP:当我在 Git 中指定祖先提交对象时,我对 HEAD^ 和 HEAD~ 感到困惑。

Git 中的 HEAD^ 和 HEAD~ 有什么区别?

HEAD^(Caret) 和(Tilde)之间的区别HEAD~在于它们如何从指定的起点向后遍历历史,在本例中是HEAD

波形符~

<rev>~[<n>]= 选择<n>th一代祖先,仅跟随第一个*父母

插入符号^

<rev>^[<n>]= 选择<n>th第一代祖先的父母

*第一个父级始终是合并的左侧,例如合并到的分支上的提交。

将 ~ 和 ^ 连接在一起

如下图所示,两个选择器~^可以组合使用。另请注意,可以使用任何常规引用,例如分支标记甚至提交哈希,而HEAD不是作为起点。

此外,根据要选择的祖先,^~可以互换使用,如下表所示。

Git中的相对引用图解

资料来源:可以在这篇关于该主题的博客文章中找到完整的概要。


Wea*_*ter 11

TLDR

〜是你大多数时候想要的,它引用过去提交到当前分支

^引用父级(git-merge创建第二个父级或更多)

A~总是和A ^
A一样~~总是和A ^^相同,所以
A~2与A ^ 2不一样,
因为~2是~~的缩写,
而^ 2不是任何事情的简写,它意味着第二个父母


kni*_*ttl 10

HEAD ^^^与HEAD~3相同,选择HEAD之前的第三次提交

HEAD ^ 2指定合并提交中的第二个头


Ric*_*ich 9

^ BRANCH 选择器
git checkout HEAD^2
通过移动到所选分支(在提交树上向后退一步)来选择(合并)提交的第二个分支

~ COMMIT 选择器
git checkout HEAD~2
在默认/选定分支上向后移动 2 个提交


将 ~ 和 ^ 相对引用定义为 PARENT 选择器是迄今为止我在互联网上遇到的主流定义 - 包括官方的 Git 书籍。是的,它们是 PARENT 选择器,但是这个“解释”的问题是它完全违背我们的目标:这就是如何区分两者......:)

另一个问题是当我们被鼓励使用 ^ BRANCH 选择器进行 COMMIT 选择时(又名 HEAD^ === HEAD~)。
再说一遍,是的,您可以这样使用它,但这不是它的设计目的。^ BRANCH 选择器的向后移动行为是副作用,而不是其目的。

仅在合并提交时,可以为 ^ BRANCH 选择器分配一个数字。因此,只有在需要在分支之间进行选择的情况下才能充分利用其容量。在分叉中表达选择的最直接方法是步入选定的路径/分支 - 这是在提交树上向后退一步。这只是一个副作用,而不是其主要目的。


Die*_*ias 8

  • HEAD~指定"分支"上的第一个父级

  • HEAD ^允许您选择提交的特定父级

一个例子:

如果你想跟随一个侧支,你必须指定类似的东西

master~209^2~15
Run Code Online (Sandbox Code Playgroud)


小智 8

HEAD~ 和 HEAD^ 区别的一个实际例子:

HEAD^ VS HEAD~


小智 5

~意思是父母。

^如果它有两个或多个父项,例如合并提交。我们可以选择父级的第二个或另一个。

因此,如果只有一个像 (HEAD~ 或 HEAD^) 的东西,它具有相同的结果。