Development Tip

Git에서 HEAD ^와 HEAD ~의 차이점은 무엇입니까?

yourdevel 2020. 9. 30. 11:32
반응형

Git에서 HEAD ^와 HEAD ~의 차이점은 무엇입니까?


Git에서 조상 커밋 객체를 지정할 때 HEAD^HEAD~.

둘 다 같은 "번호"버전이 HEAD^3HEAD~2.

나에게는 매우 비슷하거나 똑같아 보이지만 물결표와 캐럿 사이에 차이점이 있습니까?


경험의 규칙

  • 사용 ~세대의 숫자, 당신이 원하는 일반적으로 어떻게 돌아 가야 - 대부분의 시간을
  • ^병합 커밋에 사용 — 둘 이상의 (즉시) 부모가 있기 때문입니다.

기억술:

  • 물결표 ~는 모양이 거의 선형이며 직선으로 뒤로 가고자합니다.
  • 캐럿 ^은 도로에있는 나무 나 포크의 흥미로운 부분을 제안합니다.

틸데

의 "지정 개정"섹션 git rev-parse문서 를 정의 ~

<rev>~<n>예를 들어master~3 개정 매개 변수에
대한 접미사 는 첫 번째 부모 다음에 오는 명명 된 커밋 객체 ~<n>n 세대 조상 인 커밋 객체를 의미합니다 . [예를 들어] <rev>~3동등 <rev>^^^동등하다 <rev>^1^1^1...

뿐만 아니라 모든 커밋의 부모에게 도달 할 수 있습니다 HEAD. 또한 세대를 통해 뒤로 이동할 수도 있습니다. 예를 들어, master~2병합 커밋에서 첫 번째 부모를 선호하는 마스터 브랜치 팁의 조부모를 의미합니다.

탈자 부호

Git 히스토리는 비선형입니다 : 방향성 비순환 그래프 (DAG) 또는 트리입니다. A에 대한 하나의 부모 커밋 rev~rev^같은 일을 의미한다. 캐럿 선택기는 병합 커밋에 유용합니다. 각 커밋은 둘 이상의 부모의 자식이고 생물학에서 차용 한 언어를 변형시키기 때문입니다.

HEAD^현재 분기 팁의 첫 번째 직계 부모를 의미합니다 . HEAD^은의 약자이며 적절하게 HEAD^1주소를 지정할 수도 있습니다 HEAD^2. 문서동일한 섹션에서 다음git rev-parse 과 같이 정의합니다.

<rev>^, 예를 들면 HEAD^ ,v1.5.1^0
접미사 ^개정 파라미터는 객체 커밋의 제 부모를 의미한다. n 번째 부모를 ^<n>의미합니다 ([ ] ). 특별한 규칙으로 커밋 자체를 의미하며 커밋 객체를 참조하는 태그 객체의 객체 이름 일 때 사용됩니다 .<rev>^<rev>^1<rev>^0<rev>

이러한 지정자 또는 선택자는 임의로 연결될 수 있습니다. 예를 들어 , topic~3^2영어에서는 현재 분기 팁의 증조부모 (3 세대 전) 인 병합 커밋의 두 번째 부모가 topic됩니다.

의 전술 섹션 git rev-parse문서는 개념적인 자식의 역사를 통해 많은 경로를 추적합니다. 시간은 일반적으로 아래쪽으로 흐릅니다. 커밋 D, F, B 및 A는 병합 커밋입니다.

다음은 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

아래 코드를 실행하여 기록이 인용 된 그림과 일치하는 git 저장소를 만듭니다.

#! /usr/bin/env perl

use strict;
use warnings;
use subs qw/ postorder /;
use File::Temp qw/ mkdtemp /;

my %sha1;
my %parents = (
  A => [ qw/ B C /               ],
  B => [ qw/     D E F /         ],
  C => [ qw/         F /         ],
  D => [ qw/           G H /     ],
  F => [ qw/               I J / ],
);

sub postorder {
  my($root,$hash) = @_;
  my @parents = @{ $parents{$root} || [] };
  postorder($_, $hash) for @parents;
  return if $sha1{$root};
  @parents = map "-p $sha1{$_}", @parents;
  chomp($sha1{$root} = `git commit-tree @parents -m "$root" $hash`);
  die "$0: git commit-tree failed" if $?;
  system("git tag -a -m '$sha1{$root}' '$root' '$sha1{$root}'") == 0 or die "$0: git tag failed";
}

$0 =~ s!^.*/!!;  # / fix Stack Overflow highlighting
my $repo = mkdtemp "repoXXXXXXXX";
chdir $repo or die "$0: chdir: $!";
system("git init") == 0               or die "$0: git init failed";
chomp(my $tree = `git write-tree`);      die "$0: git write-tree failed" if $?;

postorder 'A', $tree;
system "git update-ref HEAD   $sha1{A}"; die "$0: git update-ref failed" if $?;
system "git update-ref master $sha1{A}"; die "$0: git update-ref failed" if $?;

# for browsing history - http://blog.kfish.org/2010/04/git-lola.html
system "git config alias.lol  'log --graph --decorate --pretty=oneline --abbrev-commit'";
system "git config alias.lola 'log --graph --decorate --pretty=oneline --abbrev-commit --all'";

새로운 일회용 저장소에 별칭을 추가하기 만하면 다음 git lolgit lola 같이 기록을 볼 수 있습니다.

$ git lol
*   29392c8 (HEAD -> master, tag: A) A
|\
| * a1ef6fd (tag: C) C
| |
|  \
*-. \   8ae20e9 (tag: B) B
|\ \ \
| | |/
| | *   03160db (tag: F) F
| | |\
| | | * 9df28cb (tag: J) J
| | * 2afd329 (tag: I) I
| * a77cb1f (tag: E) E
*   cd75703 (tag: D) D
|\
| * 3043d25 (tag: H) H
* 4ab0473 (tag: G) G

컴퓨터에서 SHA-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

에서 "지정 개정" git rev-parse문서는 좋은 정보가 가득과 가치에 대한 깊이있는 읽기입니다. Pro Git 책에서 Git Tools-Revision Selection참조하십시오 .

부모 커밋 순서

git 자신의 기록에있는 커밋 89e4fcb0dd 는 머지 커밋이며, git show 89e4fcb0dd직계 조상의 객체 이름을 표시하는 Merge 헤더 행에서 알 수 있습니다.

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-parse89e4fcb0dd의 직계 부모를 순서대로 보여 주도록 요청하여 순서를 확인할 수 있습니다 .

$ 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>...]'

부모 만 추출 하려면 전체 해시에 예쁜 형식 %P 을 사용하십시오.

$ git log -1 --pretty=%P 89e4fcb0dd
c670b1f876521c9f7cd40184bf7ed05aad843433 649bf3a42f344e71b1b5a7f562576f911a1f7423 b67d40adbbaf4f5c4898001bf062a9fd67e43368

또는 %p축약 된 부모를 위해.

$ git log -1 --pretty=%p 89e4fcb0dd
c670b1f876 649bf3a42f b67d40adbb

차이 HEAD^HEAD~웰 (존 Loeliger 의해) 션에 의해 설명된다 발견 http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html .

이 문서는 초보자에게 약간 모호 할 수 있으므로 아래 그림을 재현했습니다.

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

모두 ~^자신에 커밋의 부모를 참조 ( ~~^^조부모 등, 커밋에 모두 참조) 그러나 그들이이 숫자와 함께 사용될 때 의미에서 차이 :

  • ~2커밋에 둘 이상의 부모가있는 경우 첫 번째 부모를 통해 계층 구조에서 두 수준 위로를 의미 합니다.

  • ^2커밋에 둘 이상의 부모 가있는 두 번째 부모를 의미 합니다 (즉, 병합이기 때문에).

그래서 이들은, 결합 될 수 HEAD~2^3수단 HEAD의 조부모의 세 번째 부모가 커밋 커밋.


내 2 센트 ...

여기에 이미지 설명 입력


다음은 http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde 에서 그대로 가져온 아주 좋은 설명입니다 .

ref~약칭이며 ref~1커밋의 첫 번째 부모를 의미합니다. ref~2커밋의 첫 번째 부모의 첫 번째 부모를 의미합니다. ref~3커밋의 첫 번째 부모의 첫 번째 부모의 첫 번째 부모를 의미합니다. 등등.

ref^약칭이며 ref^1커밋의 첫 번째 부모를 의미합니다. 그러나 두 가지가 다른 점은 ref^2커밋의 두 번째 부모 의미합니다 (커밋은 병합 일 때 두 부모를 가질 수 있음을 기억하십시오).

^~연산자는 결합 할 수 있습니다.

여기에 이미지 설명 입력


^<n>형식을 사용하면 커밋의 n 번째 부모를 선택할 수 있습니다 (병합 관련). ~<n>형식을 사용하면 항상 첫 번째 부모 다음에 오는 n 번째 조상 커밋을 선택할 수 있습니다. 몇 가지 예는 git-rev-parse 의 문서를 참조하십시오 .


git에는 "from-where-you-came"/ "want-to-go-now-now"를 추적하는 구문도 있습니다. 예를 들어 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

An example could be that I did local-commits a->b->c->d and then I went back discarding 2 commits to check my code - git reset HEAD~2 - and then after that I want to move my HEAD back to d - git reset HEAD@{1}.


Simplistically:

  • ~ specifies ancestors
  • ^ specifies parents

You can specify one or more branches when merging. Then a commit has two or more parents and then ^ is useful to indicate parents.

Suppose you are on branch A and you have two more branches: B and C.

On each branch the three last commits are:

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

If now on branch A you execute the command:

git merge B C

then you are combining three branches together (here your merge commit has three parents)

and

~ indicates the n'th ancestor in the first branch, so

  • HEAD~ indicates A3
  • HEAD~2 indicates A2
  • HEAD~3 indicates A1

^ indicates the n'th parent, so

  • HEAD^ indicates A3
  • HEAD^2 indicates B3
  • HEAD^3 indicates C3

The next use of ~ or ^ next to each other is in the context of the commit designated by previous characters.

Notice 1:

  • HEAD~3 is always equal to: HEAD~~~ and to: HEAD^^^ (every indicates A1),

        and generally:

  • HEAD~n is always equal to: HEAD~...~ (n times ~) and to: HEAD^...^ (n times ^).

Notice 2:

  • HEAD^3 is not the same as HEAD^^^ (the first indicates C3 and the second indicates A1),

        and generally:

  • HEAD^1 is the same as HEAD^,
  • but for n > 1: HEAD^n is always not the same as HEAD^...^ (n times ~).

TLDR

~ is what you want most of the time, it references past commits to the current branch

^ references parents (git-merge creates a 2nd parent or more)

A~ is always the same as A^
A~~ is always the same as A^^, and so on
A~2 is not the same as A^2 however,
because ~2 is shorthand for ~~
while ^2 is not shorthand for anything, it means the 2nd parent


HEAD^^^ is the same as HEAD~3, selecting the third commit before HEAD

HEAD^2 specifies the second head in a merge commit


  • HEAD~ specifies the first parent on a "branch"

  • HEAD^ allows you to select a specific parent of the commit

An Example:

If you want to follow a side branch, you have to specify something like

master~209^2~15

actual example of the difference between HEAD~ and HEAD^

HEAD ^ VS HEAD ~


Simply put, for the first level of parentage (ancestry, inheritance, lineage, etc.) HEAD^ and HEAD~ both point to the same commit, which is (located) one parent above the HEAD (commit).

Furthermore, HEAD^ = HEAD^1 = HEAD~ = HEAD~1. But HEAD^^ != HEAD^2 != HEAD~2. Yet HEAD^^ = HEAD~2. Read on.

Beyond the first level of parentage, things get trickier, especially if the working branch/master branch has had merges (from other branches). There is also the matter of syntax with the caret, HEAD^^ = HEAD~2 (they're equivalent) BUT HEAD^^ != HEAD^2 (they're two different things entirely).

Each/the caret refers to the HEAD's first parent, which is why carets stringed together are equivalent to tilde expressions, because they refer to the first parent's (first parent's) first parents, etc., etc. based strictly on the number on connected carets or on the number following the tilde (either way, they both mean the same thing), i.e. stay with the first parent and go up x generations.

HEAD~2 (or HEAD^^) refers to the commit that is two levels of ancestry up/above the current commit (the HEAD) in the hierarchy, meaning the HEAD's grandparent commit.

HEAD^2, on the other hand, refers NOT to the first parent's second parent's commit, but simply to the second parent's commit. That is because the caret means the parent of the commit, and the number following signifies which/what parent commit is referred to (the first parent, in the case when the caret is not followed by a number [because it is shorthand for the number being 1, meaning the first parent]). Unlike the caret, the number that follows afterwards does not imply another level of hierarchy upwards, but rather it implies how many levels sideways, into the hierarchy, one needs to go find the correct parent (commit). Unlike the number in a tilde expression, it is only one parent up in the hierarchy, regardless of the number (immediately) proceeding the caret. Instead of upward, the caret's trailing number counts sideways for parents across the hierarchy [at a level of parents upwards that is equivalent to the number of consecutive carets].

따라서 HEAD ^ 3은 HEAD 커밋의 세 번째 부모와 동일합니다 (증조부모는 아닙니다. HEAD ^^^ AND HEAD ~ 3은 ...).


~ 이것은 부모의 부모를 의미합니다.

^ 병합 커밋과 같이 부모가 둘 이상인 경우 두 번째 또는 다른 부모를 선택할 수 있습니다.

따라서 (HEAD ~ 또는 HEAD ^)와 같은 것이 하나만 있으면 동일한 결과가 나타납니다.

참고 URL : https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git

반응형