git의 semi-secret 빈 트리 객체는 신뢰할 수 있으며 왜 상징적 인 이름이 없습니까?


125

Git에는 SHA1이 다음과 같은 잘 알려진 또는 적어도 잘 알려진 빈 트리가 있습니다.

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(당신은 어떤 REPO에서도 새로 만든 하나를이 볼 수 git cat-file -tgit cat-file -p).

열심히 일하고 매우 조심한다면이 빈 트리를 사용하여 파일이없는 디렉터리를 저장할 수 있습니다 ( git 저장소에 빈 디렉터리를 추가하는 방법에 대한 답변 참조 ). 실제로 좋은 생각은 아닙니다.

git diff-tree샘플 후크 중 하나가하는에 대한 하나의 인수로 더 유용합니다 .

제가 궁금한 것은

  1. 이것이 얼마나 신뢰할 수 4b825dc642cb6eb9a060e54bf8d69288fbee4904있는가? 즉, 어떤 미래 버전의 git에 git 객체에 번호가 매겨지지 않을 것인가?
  2. 빈 나무에 대한 상징적 이름이없는 이유는 무엇입니까?

(상징적 이름을 만드는 빠르고 더러운 방법은 예를 들어 SHA1을 넣는 것 .git/Nulltree입니다. 불행히도 모든 저장소에 대해이 작업을 수행해야합니다. 스크립트 등에 매직 넘버를 넣는 것이 더 나은 것 같습니다. 저는 일반적인 혐오감을 가지고 있습니다. 매직 넘버에.)


3
해시를 기억하십시오 ;-) use SHA1 ( "tree 0 \ 0") = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 (\ 0은 NUL 문자)
Thomas

4
@Thomas :이 git hash-object -t tree /dev/null방법 (아래 VonC의 답변에서)은 예를 들어 향후 버전의 git이 SHA-2로 전환되는 경우 SHA-1을 하드 코딩하지 않는 이점이 있습니다. (나는 그것이 언제 일어날 지 예측하지 않을 것입니다. :-) Mercurial을 SHA-2로 바꾸는 것이 더 쉬울 것입니다. 그들이 그것을위한 공간을 남겨 두었 기 때문입니다.)
torek

당신이 옳지 만 그것은 "쓸모없는 지식"의 좋은 조각이며 어떤 경우에도 다른 사람에게 도움이 될 수 있습니까?!
Thomas

2
@Thomas : 해시 알고리즘 전환이 예상보다 빨리 발생할 수있는 것 같습니다 . :-)
torek

"Git의 미래 버전"에 대해 말하면 내 2012 답변에 대한 최신 (2017 년 12 월) 편집에 관심이있을 것 같습니다. stackoverflow.com/revisions/9766506/7
VonC

답변:


104

이 스레드 는 다음을 언급합니다.

빈 트리 sha1을 기억하지 못하는 경우 언제든지 다음과 같이 파생 할 수 있습니다.

git hash-object -t tree /dev/null

또는 Ciro Santilli 가 의견에서 제안한 대로 :

printf '' | git hash-object --stdin -t tree

또는 여기 에서 볼 수 있듯이 Colin Schimmelfing에서 :

git hash-object -t tree --stdin < /dev/null

따라서 해당 명령의 결과로 변수를 빈 sha1 트리 ( "잘 알려진 값"에 의존하는 대신)로 정의하는 것이 더 안전하다고 생각합니다.

참고 : Git 2.25.1 (2020 년 2 월)은 커밋 9c8a294 에서 제안합니다 .

empty_tree=$(git mktree </dev/null)
# Windows:
git mktree <NUL

그리고 추가 :

역사적 메모로, 현재 알려진 함수 repo_read_object_file()346245a1bb ( "빈 트리 객체 하드 코딩", 2008-02-13, Git v1.5.5-rc0- merge ) 에서 빈 트리를 학습했으며 현재 알려진 함수는 로가 oid_object_info()에 빈 트리를 배웠습니다 c4d9986f5f ( " sha1_object_info: 검사 cached_object도 가게를", 2011-02-07, 힘내 v1.7.4.1).


작성자가 첫 번째 커밋을 비우기를 원할 때 일부 GitHub 저장소에 SHA1 팝업이 표시됩니다 (블로그 게시물 " How I initialize my Git repositories "참조).

$ GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000" GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000" git commit --allow-empty -m 'Initial commit'

당신에게 줄 것입니다 :

빈 트리 SHA1

(트리 SHA1 참조?)

빈 커밋 위에 기존 히스토리를 리베이스 할 수도 있습니다 ( " git : 커밋을 첫 번째로 삽입하는 방법, 나머지는 모두 이동? "참조).

두 경우 모두 빈 트리의 정확한 SHA1 값에 의존하지 않습니다. 첫 번째 빈 커밋으로 저장소를 초기화
하는 모범 사례 를 따르기 만하면 됩니다.


하기 위해서:

git init my_new_repo
cd my_new_repo
git config user.name username
git config user.email email@com

git commit --allow-empty -m "initial empty commit"

그러면 리포지토리, 사용자 이름, 이메일, 생성 날짜와 관련된 SHA1이있는 커밋이 생성됩니다 (즉, 커밋 자체의 SHA1은 매번 달라짐).
그러나 해당 커밋이 참조하는 트리는 4b825dc642cb6eb9a060e54bf8d69288fbee4904빈 트리 SHA1이됩니다.

git log --pretty=raw

commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <vonc@laposte.net> 1381232247 +0200
committer VonC <vonc@laposte.net> 1381232247 +0200

    initial empty commit

커밋 트리 만 표시하려면 (커밋 트리 SHA1 표시) :

git show --pretty=format:%T 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
4b825dc642cb6eb9a060e54bf8d69288fbee4904

빈 트리를 참조하는 커밋이 실제로 첫 번째 커밋 인 경우 다음을 사용하여 빈 트리 SHA1을 표시 할 수 있습니다.

git log --pretty=format:%h --reverse | head -1 | xargs git show --pretty=format:%T
4b825dc642cb6eb9a060e54bf8d69288fbee4904

(Windows에서도 Gnu On Windows 명령으로 작동 합니다)


마찬가지로 아래 주석 사용 git diff <commit> HEAD이 현재 지점 HEAD에있는 모든 파일을 표시합니다 :

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

참고 : 빈 트리 값은 cache.h.

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Git 2.16 (Q1 2018) 이후 커밋 eb0ccfd 에서 볼 수 있듯이 더 이상 SHA1에만 연결되지 않는 구조에서 사용됩니다 .

해시 추상화를 사용하도록 빈 트리 및 Blob 조회 전환

의 용도를 전환 empty_tree_oid하고 empty_blob_oid용도에 current_hash사용되는 현재의 해시 알고리즘을 나타내는 추상화.

자세한 내용은 " Git에서 최신 SHA를 사용하지 않는 이유는 무엇입니까? ": Git 2.19 (2018 년 3 분기) 이후 SHA-2입니다 .


Git 2.25 (Q1 2020)에서는 테스트가 SHA-2 전환을 준비하고 있으며 빈 트리를 포함합니다.

참조 fa26d5e 커밋 , cf02be8 커밋 , 38ee26b 커밋 , 커밋 37ab8eb , 0370b35 커밋 , 0253e12 커밋 , 45e2ef2 커밋 , 79b0edc 커밋 , 840624f 커밋 , 32a6707 커밋 , 440bf91 커밋 , 0b408ca 커밋 , 2eabd38 커밋 (2019 10월 28일을), 및 1bcef51 커밋 , 커밋 ecde49b (2019 년 10 월 5 일) by brian m. 칼슨 ( bk2204) .
(의해 병합 Junio C 하마노 - gitster-28014c1 커밋, 2019 년 11 월 10 일)

t/oid-info: 빈 트리 및 빈 Blob 값 추가

서명자 : Brian M. Carlson

테스트 스위트는 결국 SHA-1 이외의 알고리즘을 사용하여 실행하는 방법을 학습합니다. 이를 준비하기 위해 test_oid함수 제품군에 빈 Blob 및 빈 트리 값을 조회하여 사용할 수 있도록하는 방법을 알려줍니다.

그래서 t/oid-info/hash-info지금 포함 :

rawsz sha1:20
rawsz sha256:32

hexsz sha1:40
hexsz sha256:64

zero sha1:0000000000000000000000000000000000000000
zero sha256:0000000000000000000000000000000000000000000000000000000000000000

algo sha1:sha1
algo sha256:sha256

empty_blob sha1:e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813

empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

SHA2 " 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"는 새 SHA1 " 4b825dc642cb6eb9a060e54bf8d69288fbee4904"빈 트리입니다.


@torek : 빈 트리 SHA1을 설명하기 위해 첫 번째 빈 커밋 모범 사례에 몇 가지 예제를 추가했습니다.
VonC

글쎄요, 목표 중 하나는 git diff-tree제가 작성 하고 있는 일부 스크립트에서 "빈 트리"해시를 인수로 사용하는 것입니다. 저장소에 초기 빈 커밋이 있다는 보장은 없습니다. 그래서 저는이 스크립트가 언젠가는 깨질 지 궁금합니다.
torek

1
에 전달 -w하면 git hash-object실행되는 저장소에 객체가 생성되고, 실행중인 저장소에 빈 트리가 다시 생성됩니다.
javawizard

rebase를 사용하여 첫 번째 커밋 전에 가고 싶다면 git rebase --root
GergelyPolonkai

1
또는 당신은 대신 마법의 파이프의 마법을 선호하는 경우 /dev/null: printf '' | git hash-object --stdin -t tree:)
치로 틸리을郝海东冠状病六四事件法轮功

3

해시를 찾는 두 가지 방법으로 블로그 게시물을 작성했습니다. http://colinschimmelfing.com/blog/gits-empty-tree/

어떤 이유로 든 변경된 경우 아래 두 가지 방법을 사용하여 찾을 수 있습니다. 그러나 .bashrc 별칭 등에서 해시를 사용하는 것은 매우 자신감이 있으며 조만간 변경되지 않을 것이라고 생각합니다. 최소한 git의 주요 릴리스 일 것입니다.

두 가지 방법은 다음과 같습니다.

  1. 위의 답변 : git hash-object -t tree --stdin < /dev/null
  2. 단순히 빈 저장소를 초기화하고 git write-tree새 저장소에서 실행 하면 해시가 git write-tree에 의해 출력됩니다.

로 명령을 실행하면 –-stdin저를주는 fatal: Cannot open '–-stdin': No such file or directory자식 2.7.2와 함께. 그러나 --stdinVonC의 답변에서와 같이 실행하지 않으면 해시 값이 제공됩니다
sigy

이 답변은 블로그 게시물이 이제 그다지 유용하지 않습니다. 따라서 우리는 일반적으로 SO에 대한 이러한 답변을 승인하지 않습니다.
Philip Whitehouse

1
@PhilipWhitehouse 블로그 게시물은 죽지 않았지만 어떤 경우에도 두 가지 방법을 내 대답에 포함했습니다.이 두 가지 방법을 포함하지 않으면 좋은 대답이 아니라는 데 동의합니다.
schimmy

3

저장소가 아직 비어 있지 않은 경우에도 빈 트리 커밋을 만드는 방법에 대한 답변입니다. https://stackoverflow.com/a/14623458/9361507

그러나 나는 "비어있는"태그를 선호하지만 브랜치가 아닙니다. 간단한 방법은 다음과 같습니다.

git tag empty $(git hash-object -t tree /dev/null)

태그는 커밋없이 직접 트리를 가리킬 수 있기 때문입니다. 이제 작업 트리의 모든 파일을 가져 오려면 :

git diff --name-only empty

또는 통계와 동일 :

git diff --stat empty

diff로 모든 파일 :

git diff empty

모든 파일에서 공백을 확인하십시오.

git diff --check empty

...하지만 태그 생성에 매직 넘버를 사용하여 그냥 아주 문제 질문의 양탄자에서 칫솔질 ( 하지 매직 넘버 SHA-1 사용)
RomainValeri

사실이 아니다. 나는 나무 같은 물체를 가리 키기 위해 태그를 사용했다. 이제이 tree-ish는 SHA-1에 의해 정의되며, 향후 예를 들어 SHA-256 등으로 변경 될 수 있습니다 (저장소 마이그레이션 포함). 그러나 태그는 동일합니다. :) 태그의 주요 기능은 객체를 가리키는 것입니다. 태그는 SHA-1을 내부적으로 또는 다른 것을 사용할 수 있으며 Git 내부에만 해당됩니다.
Olleg

알겠습니다. 그러나 당신 (또는 이것을 읽는 사람) (또는 스크립트 , 더 나쁜 것)이 나중에 적용하려고하면 (첫 번째 줄) 새로운 해시 알고리즘에서 실패 할 수 있습니다. 여기서 첫 번째 줄을 실행 된 표현식으로 대체합니다 (생성 이 해시)는 계속 성공할 것입니다.
RomainValeri

이것을 빈 트리 해시를 자동으로 생성하는 방법 중 하나와 결합하면 미래를 대비할 수 있습니다 (@RomainValeri가 제안한대로). 그러나 나에게 달려 있다면 git rev-parse(a) 빈 트리 해시와 (b) 널 커밋 해시를 생성하기 위해 새로운 플래그 또는 키워드 또는 그 라인을 따라 무언가를 가질 것입니다. 이 두 가지 모두 스크립트에서 유용하며 제안 된 SHA-256 변경 사항으로부터 보호합니다.
torek

좋아요, 변경되었습니다. 그러나 이것은 "가장 간단한 방법"이 아닙니다. :)
Olleg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.