programing

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

lovejava 2023. 5. 24. 21:21

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

Git에서 조상 커밋 개체를 지정하면 다음과 같이 혼동됩니다.HEAD^그리고.HEAD~.

둘 다 다음과 같은 "번호가 지정된" 버전을 가지고 있습니다.HEAD^3그리고.HEAD~2.

저랑 많이 비슷하거나 비슷한 것 같은데, 타일과 캐럿의 차이점이 있나요?

경험칙

  • 사용하다~대부분의 경우 - 여러 세대로 거슬러 올라가며, 일반적으로 원하는 것.
  • 사용하다^커밋 - 두부모가 에 - - 의상부있때기문커다니입.

니모닉:

  • ~로 한 로 가고 .
  • ^합니다.

틸데

설명서의 "개정사항 지정" 섹션은 다음을 정의합니다.~~하듯이

<rev>~<n>를 들어, 예를 들어, 기호입니다.master~3
~<n>revision 매개 변수에 대한 명령은 첫 번째 부모만 따르는 명명된 커밋 개체의 다음 세대th 조상인 커밋 개체를 의미합니다.예를들면,<rev>~3는 와동합다니등다에 합니다.<rev>^^^는 와동한등에 합니다.<rev>^1^1^1

은 단순히 약속이든 할 수 .HEAD다음과 같이 세대를 통해 다시 이동할 수도 있습니다. 예를 들어,master~2병합 커밋 시 첫 번째 부모를 선호하는 마스터 분기 팁의 조부모를 의미합니다.

캐럿

Git 이력은 비선형적입니다. DAG(방향 비순환 그래프) 또는 트리입니다.의 경우 부가한 있명커 경의 우밋는 ▁for 경우의커rev~그리고.rev^같은 뜻입니다.캐럿 선택기는 병합 커밋에서 유용하게 사용됩니다. 각 커밋은 두 명 이상의 부모의 자식이며 생물학에서 차용한 언어를 변형시키기 때문입니다.

HEAD^현재 분기 팁의 첫 번째 직접 상위 항목을 의미합니다. HEAD^는 의줄말임의 줄임말입니다.HEAD^1그리고 당신은 또한 주소를 쓸 수 있습니다.HEAD^2필요에 따라 기타 작업을 참조.설명서의 동일한 섹션에서는 다음과 같이 정의합니다.

<rev>^예를 들면 HEAD^,v1.5.1^0
^의 첫 합니다. ^<n>다음 부모th 의미합니다([예:]).<rev>^는 와동합다니등다에 합니다.<rev>^1). ). 특별한 규칙으로,<rev>^0커밋 자체를 의미하며 다음과 같은 경우에 사용됩니다.<rev>커밋 개체를 참조하는 태그 개체의 개체 이름입니다.

이러한 지정자 또는 선택자는 임의로 체인될 수 있습니다. 예를 들어,topic~3^2의 현재 전의 두 입니다.topic.

앞서 설명한 설명서의 섹션에서는 개념적 깃 이력을 통해 많은 경로를 추적합니다.시간은 일반적으로 아래로 흐릅니다.커밋 D, F, B 및 A는 병합 커밋입니다.

여기 존 뢰리거의 삽화가 있습니다.커밋 노드 B와 C는 모두 커밋 노드 A의 상위 노드입니다.오른쪽으로 (. 위밋커오정다니렬됩로으. (N.B.)git log --graph명령은 기록을 반대 순서로 표시합니다.)

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

아래 코드를 실행하여 따옴표로 묶은 그림과 기록이 일치하는 깃 저장소를 만듭니다.

#! /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 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

설명서의 "개정사항 지정"은 훌륭한 정보로 가득 차 있으며 자세히 읽을 가치가 있습니다.Pro Git 책에서 Git 도구 - 개정 선택을 참조하십시오.

상위 커밋 순서

git 자체 이력에서 커밋 89e4fcb0dd는 병합 커밋입니다.git show 89e4fcb0dd인접한 조상의 개체 이름을 표시하는 병합 헤더 행을 나타냅니다.

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의 부모는 다음과 같습니다.

$ 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~http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html 에서 볼 수 있는 (Jon Loeliger의) 그림에 잘 설명되어 있습니다.

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

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커밋의 두 번째 부모를 의미합니다(따라서 커밋은 병합될 때 두 개의 부모를 가질 수 있습니다).

^그리고.~연산자를 결합할 수 있습니다.

여기에 이미지 설명 입력

간단히 말해:

  • ~ 조상지를 지정합니다.
  • ^parents 을 합니다.

병합할 때 하나 이상의 분기를 지정할 수 있습니다.그러면 커밋에는 두 명 이상의 부모가 있고 그 다음에는^부모를 나타내는 데 유용합니다.

A 지점에 있고 B 지점과 C 지점이 두 개 더 있다고 가정합니다.

각 분기에서 마지막 3개 커밋은 다음과 같습니다.

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

이제 분기 A에서 다음 명령을 실행합니다.

git merge B C

그런 다음 세 개의 분기를 함께 결합합니다(여기서 병합 커밋에는 세 개의 부모가 있음).

그리고.

~첫 번째 분기의 n번째 조상을 나타냅니다.

  • HEAD~A3를 나타냄
  • HEAD~2A2를 나타냄
  • HEAD~3A1을 나타냄

^부모가 아님을 나타냅니다.

  • HEAD^A3를 나타냄
  • HEAD^2B3를 나타냄
  • HEAD^3C3를 나타냅니다.

의 다음 ~또는^서로 옆에 있는 것은 이전 캐릭터가 지정한 커밋의 맥락입니다.

공지사항 1:

  • HEAD~3 다음과.HEAD~~~ 대상:HEAD^^^(매번 A1 표시),

그리고 일반적으로:

  • HEAD~n 다음과.HEAD~...~(n회)~및 ) 및대상:HEAD^...^(n회)^).

공지사항 2:

  • HEAD^3 동일하지 않습니다.HEAD^^^(첫 번째는 C3을 나타내고 두 번째는 A1을 나타냅니다.)

그리고 일반적으로:

  • HEAD^1는 와동합다니와 .HEAD^,
  • 그러나 n > 1의 경우:HEAD^n항상 같지는 않습니다.HEAD^...^(n회)^).

^<n>format을 사용하여 커밋의 n번째 상위 항목(병합 포함)을 선택할 수 있습니다.~<n>format을 사용하면 항상 첫 번째 부모를 따라 n번째 조상 커밋을 선택할 수 있습니다.몇 가지 예는 git-rev-parse의 설명서를 참조하십시오.

에는 " git는를예를들어에다기니추있하위 "from-where-you-come"/"want-to-go-back-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

를 들어 로컬 한 후 가 있습니다. - 예 들 a->b->c->d 를 개 후 코 2 의 위 커 기 확 다 돌git reset HEAD~2그 다음엔 머리를 다시 d로 돌리고 싶어요git reset HEAD@{1}.

HEAD~와 HEAD^의 차이에 대한 실제 예:

HEAD^ VS HEAD~

TLDR

대부분의 경우 원하는 것입니다. 현재 분기에 대한 과거 커밋을 참조합니다.

상위 항목 참조(git-interval은 두 번째 상위 항목 이상을 생성함)

A^A~와 .
A, 따라서 A~~~는 A^^와 같습니다.
는 A A~2는 A^2입니다.
2의 이기 때문입니다.
^2는 어떤 것의 줄임말이 아니지만, 그것은 두 번째 부모를 의미합니다.

HEAD^^^는 와동합다니와 .HEAD~3HEADHEAD 에 세

HEAD^2의 두 합니다.

  • HEAD~는 "지점"의 첫 번째 부모를 지정합니다.

  • HEAD^를 사용하면 커밋의 특정 상위 항목을 선택할 수 있습니다.

예:

곁가지를 따라가려면 다음과 같은 것을 지정해야 합니다.

master~209^2~15

OP: Git에서 조상 커밋 개체를 지정하면 HEAD^와 HEAD~가 혼동됩니다.

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

HEAD^ 및 () »HEAD~인데, 이 (틸데)라는 특정한 경우에는 역사를 뒤로 이동합니다.HEAD.

틸데~

<rev>~[<n>]<n>th 번째* 부모님만 , * 릅니다따상조.

캐럿 ^

<rev>^[<n>]<n>th 조상의 1세대 조상의

*첫 번째 상위 항목은 항상 병합의 왼쪽에 있습니다(예: 병합된 분기의 커밋).

~ 및 ^ 함께 가입

아래 그림에서 볼 수 있듯이 두 셀렉터 ~와 ^를 함께 사용할 수 있습니다.또한 를 사용하는 대신HEAD시작점으로 분기, 태그 또는 커밋 해시와 같은 모든 일반 참조를 사용할 수 있습니다.

또한 선택하고자 하는 조상에 따라 아래 표와 같이 ^과 ~를 서로 바꾸어 사용할 수 있습니다.

Git의 상대적 참조 그림

출처: 이 주제에 대한 자세한 내용은 이 블로그 게시물에서 확인할 수 있습니다.

BRANCH
git checkout HEAD^2
선택한 분기로 이동하여 커밋의 두 번째 분기를 선택합니다(커밋 트리에서 한 단계 뒤로 이동).

COMMIT
HEAD~2git checkout HEAD~2개
branch에서 2 커밋을 합니다.


~ 및 ^ 상대 참조를 모두 부모 선택기로 정의하는 것은 공식 Git Book을 포함하여 지금까지 인터넷에서 발표된 모든 곳에서 지배적인 정의입니다.네, 그들은 부모 선택자이지만, 이 "설명"의 문제는 우리의 목표인 두 가지를 어떻게 구별하느냐에 완전히 어긋난다는 것입니다.:)

또 다른 문제는 COMMIT 선택(일명 HEAD^ === HEAD~)에 ^ BRANCH 선택기를 사용하도록 권장되는 경우입니다.
다시 말하지만, 네, 이런 식으로 사용할 수는 있지만, 이것은 설계된 목적이 아닙니다.^ 분기 선택기의 역방향 이동 동작은 그 목적이 아닌 부작용입니다.

병합된 커밋에서만 ^ BRANCH 선택기에 번호를 할당할 수 있습니다.따라서 분기 중에서 선택해야 하는 경우에만 전체 용량을 사용할 수 있습니다.그리고 포크로 선택 항목을 표현하는 가장 간단한 방법은 선택한 경로/분기로 이동하는 것입니다. 이는 커밋 트리에서 한 단계 뒤로 이동하는 것입니다.그것은 단지 부작용일 뿐, 주된 목적은 아닙니다.

~부모를 의미합니다.

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

따라서 (HEAD~ 또는 HEAD^)와 같은 것 하나만 있어도 같은 결과를 얻을 수 있습니다.

입력할지 여부를 고민하는 경우HEAD^또는HEAD~명령에서 다음 중 하나를 사용합니다.

현재 커밋의 첫 번째 부모인 동일한 커밋의 이름입니다.

로 마가지로찬.master~그리고.master^두 이름 모두 마스터의 첫 번째 부모 이름입니다.

와 같은 으로.2 + 2그리고.2 x 2둘 다입니다4그들은 그곳에 가는 방법이 다르지만, 답은 같습니다.

다음과 같은 질문에 답합니다.Git에서 HEAD^와 HEAD~의 차이점은 무엇입니까?

병합을 방금 했거나(따라서 현재 커밋에 두 개 이상의 부모가 있음) 캐럿과 타일이 작동하는 방식에 여전히 관심이 있는 경우 다른 답변(여기서는 복제하지 않음)과 반복적으로 사용하는 방법(예:HEAD~~~) 또는숫예자예()로 HEAD^2, 이으로 시간을 할 수 있기를 그렇지 않으면 이 답변으로 시간을 절약할 수 있기를 바랍니다.

간단히 말해서, 첫 번째 수준의 부모(조상, 상속, 혈통 등) HEAD^ 및 HEAD~는 모두 HEAD(커밋) 위에 하나의 부모(위치)가 있는 동일한 커밋을 가리킵니다.

또한 HEAD^ = HEAD^1 = HEAD~ = HEAD~1.그런데 HEAD^^!=HEAD^2!=HEAD~2.아직 HEAD^^ =HEAD~2.계속 읽어보세요.

상위 계층의 첫 번째 수준을 넘어서면 특히 작업 분기/마스터 분기가 (다른 분기에서) 병합된 경우 상황이 더 까다로워집니다.캐럿인 HEAD^^ =HEAD~2(동등함)와 구문 문제도 있지만 HEAD=!^^HEAD^2(전혀 다른 두 가지)입니다.

각/캐럿은 HEAD의 첫 번째 부모를 나타냅니다. 따라서 함께 문자열로 묶인 캐럿은 연결된 캐럿의 수 또는 타일 뒤에 오는 숫자(둘 다 동일한 의미)를 기준으로 첫 번째 부모(첫 번째 부모)의 첫 번째 부모 등을 엄격하게 참조하기 때문입니다.첫 번째 부모와 함께 지내며 x세대로 올라갑니다.

HEAD~2(또는 HEAD^^)는 계층 구조에서 현재 커밋(HEAD) 위/위에 있는 두 단계의 조상인 커밋을 의미하며, HEAD의 조부모 커밋을 의미합니다.

반면 HEAD^2는 첫 번째 부모의 두 번째 부모의 커밋이 아니라 두 번째 부모의 커밋을 의미합니다.이는 캐럿이 커밋의 부모를 의미하고, 뒤에 오는 숫자는 어떤 부모 커밋을 참조하는지를 의미하기 때문입니다(캐럿이 숫자 뒤에 숫자가 붙지 않는 경우에는 [1, 첫 번째 부모를 의미하기 때문에].캐럿과 달리 뒤에 오는 숫자는 계층이 위쪽으로 올라가는 또 다른 수준을 의미하는 것이 아니라 계층에 있는 올바른 부모(커밋)를 찾아야 하는 측면의 수준 수를 의미합니다.타일드 식의 숫자와는 달리 캐럿을 진행하는 숫자(즉시)에 관계없이 계층 구조에서 상위 한 개의 부모만 됩니다.캐럿의 후행 번호는 계층 전반에 걸쳐 부모(연속 케어 횟수와 동일한 상위 부모 수준)에 대해 옆으로 계산됩니다.

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

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