힘내에서 개체를 커밋 할 때 내가 조상을 지정, 나는 사이에 혼동하고있어 HEAD^
및 HEAD~
.
둘 다 같은 "번호"버전이 HEAD^3
와 HEAD~2
.
그들은 나에게 매우 유사하거나 똑같아 보이지만 물결표와 캐럿 사이에 차이점이 있습니까?
힘내에서 개체를 커밋 할 때 내가 조상을 지정, 나는 사이에 혼동하고있어 HEAD^
및 HEAD~
.
둘 다 같은 "번호"버전이 HEAD^3
와 HEAD~2
.
그들은 나에게 매우 유사하거나 똑같아 보이지만 물결표와 캐럿 사이에 차이점이 있습니까?
답변:
~
대부분의 시간을 사용 하여 여러 세대 (일반적으로 원하는 것)로 되돌아갑니다.^
병합 커밋에 사용 -둘 이상의 (즉시) 부모가 있기 때문에기억술:
~
모양은 거의 선형이며 직선으로 뒤로 가고 싶습니다.^
은 도로에서 나무 나 포크의 흥미로운 부분을 제안합니다의 "지정 개정"섹션 git rev-parse
문서 를 정의 ~
로
<rev>~<n>
예master~3
접미사~<n>
개정 파라미터는이 오브젝트 저지 수단 인 N 번째 지정된 발생 조상 만 시조 따라 오브젝트를 저지한다. 예를 들어,<rev>~3
동등<rev>^^^
동등하다<rev>^1^1^1
...
뿐만 아니라 모든 커밋의 부모에게 갈 수 있습니다 HEAD
. 예를 들어, master~2
마스터 커밋 팁의 조부모를 의미하며 병합 커밋에서 첫 번째 부모를 선호합니다.
Git 히스토리는 비선형 : DAG (Directed Acyclic Graph) 또는 트리입니다. 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
영어 병합의 두 번째 부모가에 그 (삼대 다시) 지점의 현재 팁의 증조 할아버지 커밋 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
아래 코드를 실행하여 인용 된 그림과 히스토리가있는 자식 저장소를 만듭니다.
#! /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
과git 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-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
^^^^^^^
대신에 사용 하는 것이 매우 편리하지 ~7
않습니까? 그것이 ~
유용한 이유 입니다
차이 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
F = A^2^
.
^ == ^1 == LEFTMOST PARENT
, ^2 == SECOND LEFTMOST PARENT
이리저리 때문에. 그리고 ~ == ~1 == LEFTMOST PARENT
, ~2 == LEFTMOST PARENTS LEFTMOST PARENT == LEFTMOST GRANDPARENT
. 확장하여~2^2 == LEFTMOST GRANDPARENTS SECOND LEFTMOST PARENT
모두 ~
와 ^
자신에 커밋의 부모를 참조 ( ~~
와 ^^
조부모 등, 커밋에 모두 참조) 그러나 그들이이 숫자와 함께 사용될 때 의미에서 차이 :
~2
커밋에 둘 이상의 부모가있는 경우 첫 번째 부모를 통해 계층 구조에서 두 수준을 의미 합니다.
^2
커밋에 둘 이상의 부모 가있는 두 번째 부모를 의미 합니다 (즉 병합이기 때문에)
그래서 이들은, 결합 될 수 HEAD~2^3
수단 HEAD
의 조부모의 세 번째 부모가 커밋 커밋.
^^
과 동일 ^2
하지만 아니다.
내 두 센트 ...
H=A~2^2
하지 H=A~2^1
?
A
, B
, D
, G
같은 지점에 있고 커밋 D
(A)의 병합입니다 G
및 H
따라서 두 부모를 가진. 따라서 H
다른 분기 의 커밋 ( ) 은로 참조됩니다 ^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-come"/ "want-to-go-back-now"를 추적하기위한 구문을 가지고 있음을 주목할 가치가 있습니다. 예를 들어, HEAD@{1}
새로운 커밋 위치로 점프 한 곳을 참조 할 것입니다.
기본적으로 HEAD@{}
변수는 HEAD 이동 히스토리를 캡처하며 명령을 사용하여 git의 참조를 조사하여 특정 헤드를 사용하도록 결정할 수 있습니다 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
다시 HEAD를 d-로 옮기고 싶습니다 git reset HEAD@{1}
.
간단하게 :
~
조상을 지정^
부모를 지정병합 할 때 하나 이상의 분기를 지정할 수 있습니다. 그런 다음 커밋에는 둘 이상의 부모가 있으며 ^
부모를 나타내는 데 유용합니다.
분기 A에 있고 B 및 C 라는 두 개의 분기가 더 있다고 가정하십시오 .
각 브랜치에서 세 가지 마지막 커밋은 다음과 같습니다.
이제 지점 A에 있으면 다음 명령을 실행하십시오.
git merge B C
그런 다음 세 가지를 결합합니다 (여기서 병합 커밋에는 세 부모가 있습니다)
과
~
첫 번째 분기에서 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~...~
( N 회 ~
)하고 : HEAD^...^
( N 회 ^
).고지 2 :
HEAD^3
이다 하지 같은 HEAD^^^
((가) 제 나타내는 C3을 하고 두 번째 나타내는 A1을 )그리고 일반적으로 :
HEAD^1
와 동일합니다 HEAD^
.HEAD^n
경우 항상 ( n 번 ) 과 동일 하지 않습니다 .HEAD^...^
~
간단히 말해서, 첫 번째 레벨의 상위 (계급, 상속, 계보 등) HEAD ^ 및 HEAD ~에 대해 동일한 커밋을 가리키며, 이는 HEAD 위의 한 부모 (커밋)입니다.
또한 HEAD ^ = HEAD ^ 1 = HEAD ~ = HEAD ~ 1입니다. 그러나 HEAD ^^! = HEAD ^ 2! = HEAD ~ 2. 그러나 HEAD ^^ = HEAD ~ 2. 읽어.
첫 번째 수준의 상위 항목을 넘어 서면, 특히 작업중인 지점 / 마스터 지점이 다른 지점에서 병합 한 경우 상황이 더 까다로워집니다. 캐럿과의 구문 문제도 있습니다. HEAD ^^ = HEAD ~ 2 (동등) BUT HEAD ^^! = HEAD ^ 2 (두 가지가 완전히 다릅니다).
각 캐럿은 HEAD의 첫 번째 부모를 나타내며 연결된 캐럿의 수를 엄격하게 기준으로 첫 번째 부모의 첫 번째 부모 등을 참조하기 때문에 함께 묶인 캐럿은 물결 표식과 같습니다. 또는 물결표 뒤의 숫자 (둘 다 같은 것을 의미 함), 즉 첫 번째 부모와 함께 있고 x 세대 위로 올라갑니다.
HEAD ~ 2 (또는 HEAD ^^)는 계층 구조에서 현재 커밋 (HEAD) 위 / 위의 두 가지 상위 수준 인 커밋을 나타내며, 이는 HEAD의 조부모 커밋을 의미합니다.
반면에 HEAD ^ 2는 첫 번째 부모의 두 번째 부모의 커밋이 아니라 단순히 두 번째 부모의 커밋을 나타냅니다. 캐럿은 커밋의 부모를 의미하기 때문에 다음 숫자는 부모 커밋이 참조되는 / 무엇을 의미 하는지를 나타냅니다 (캐럿 뒤에 숫자가없는 경우 첫 번째 부모는 [숫자가 짧기 때문에) 1, 첫 번째 부모를 의미]). 캐럿과 달리 이후에 나오는 숫자는 다른 수준의 계층 구조를 위쪽으로 나타내는 것이 아니라 계층 구조에 얼마나 많은 수준의 계층 구조가 있는지를 의미하며 올바른 부모를 찾기 위해 커밋해야합니다 (커밋). 물결 표현식의 숫자와 달리, 캐럿을 진행하는 숫자 (즉시)에 관계없이 계층 구조에서 상위에 하나만 있습니다. 위쪽이 아니라 캐럿
따라서 HEAD ^ 3은 HEAD 커밋의 세 번째 부모와 같습니다 (조부모님도 아닙니다. HEAD ^^^ AND HEAD ~ 3은 ...).