Git는 파일 해시를 어떻게 계산합니까?
트리 개체에 저장된 SHA1 해시(반환된 대로)git ls-tree
) 파일 내용의 SHA1 해시와 일치하지 않습니다(반환된 대로).sha1sum
):
$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e -
Git는 파일 해시를 어떻게 계산합니까?해시를 계산하기 전에 내용을 압축합니까?
Git는 개체 앞에 "blob", 그 다음에 길이(사람이 읽을 수 있는 정수), 그 다음에 NUL 문자를 붙입니다.
$ echo -e 'blob 14\0Hello, World!' | shasum 8ab686eafeb1f44702738c8b0f24f2567c36da6d
출처: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
나는 단지 다음과 같은 대답에 대해 확장하고 있습니다.@Leif Gruenwoldt
그리고 제공된 참조에 무엇이 있는지 자세히 설명합니다.@Leif Gruenwoldt
사용자가 직접 실행
- 1단계. 리포지토리에 빈 텍스트 문서 만들기(이름은 중요하지 않음)
- 2단계. 문서 준비 및 커밋
- 3단계. 실행을 통해 블롭의 해시를 식별합니다.
git ls-tree HEAD
- 4단계. 블롭의 해시를 찾습니다.
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
- 5단계. 깜짝 놀라 아래를 읽습니다.
GIT는 커밋 해시를 어떻게 계산합니까?
Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "\0" + <contents_of_file>)
텍스트blob⎵
는 상수 접두사이고\0
또한 상수이며 다음과 같습니다.NULL
캐릭터. 그.<size_of_file>
그리고.<contents_of_file>
파일에 따라 다릅니다.
참고: git commit 개체의 파일 형식은 무엇입니까?
그리고 모두 다들!
하지만 잠깐!, 당신은 그것을 알아차렸습니까?<filename>
해시 계산에 사용되는 매개 변수가 아닙니까?두 파일의 내용이 만들어진 날짜와 시간 및 이름에 상관없이 동일한 해시를 가질 수 있습니다.이것이 Git이 다른 버전 제어 시스템보다 이동 및 이름 변경을 더 잘 처리하는 이유 중 하나입니다.
사용자가 직접 하기(Ext)
- 6단계. 다른 빈 파일을 만듭니다.
filename
같은 디렉토리에- 7단계. 두 파일의 해시를 비교합니다.
참고:
링크에는 다음과 같은 방법을 언급하지 않습니다.tree
개체가 해시됩니다.알고리즘과 매개 변수에 대해서는 확신할 수 없지만, 제 관찰에 따르면 아마도 모든 것을 기반으로 해시를 계산합니다.blobs
그리고.trees
(아마도 그들의 해시) 그것은 포함합니다.
git hash-object
다음은 테스트 방법을 빠르게 확인하는 방법입니다.
s='abc'
printf "$s" | git hash-object --stdin
printf "blob $(printf "$s" | wc -c)\0$s" | sha1sum
출력:
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f -
어디에sha1sum
GNU Coreutils에 있습니다.
그런 다음 각 개체 유형의 형식을 이해해야 합니다.우리는 이미 사소한 것들을 다루었습니다.blob
다른 것들은 다음과 같습니다.
- commit: git commit 개체의 파일 형식은 무엇입니까?
- 트리: 깃 트리 개체의 내부 형식은 무엇입니까?
- 태그: Git Tag 객체 SHA1은 어떻게 생성됩니까?
파이썬 3의 유닛 테스트를 위해 이것이 필요했기 때문에 여기에 두고 가야겠다고 생각했습니다.
def git_blob_hash(data):
if isinstance(data, str):
data = data.encode()
data = b'blob ' + str(len(data)).encode() + b'\0' + data
h = hashlib.sha1()
h.update(data)
return h.hexdigest()
나는 고수합니다\n
모든 곳의 줄 끝 부분을 제외하고 일부 환경에서는 Git이 이 해시를 계산하기 전에 줄 끝 부분을 변경할 수도 있으므로 A도 필요할 수 있습니다.
Leif Gruenwoldt 답변에 기초하여, 다음과 같은 셸 함수를 대체할 수 있습니다.
git-hash-object () { # substitute when the `git` command is not available
local type=blob
[ "$1" = "-t" ] && shift && type=$1 && shift
# depending on eol/autocrlf settings, you may want to substitute CRLFs by LFs
# by using `perl -pe 's/\r$//g'` instead of `cat` in the next 2 commands
local size=$(cat $1 | wc -c | sed 's/ .*$//')
( echo -en "$type $size\0"; cat "$1" ) | sha1sum | sed 's/ .*$//'
}
테스트:
$ echo 'Hello, World!' > test.txt
$ git hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
$ git-hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
이진 해시 계산을 위한 python3 버전입니다(위 예제는 텍스트에 대한 것입니다)
가독성을 위해 이 코드를 직접 정의합니다.또한 코드는 완전한 스크립트가 아닌 스니펫입니다.당신의 영감을 위해.
targetSize: int
exists: bool
if os.path.exists(targetFile):
exists = True
targetSize = os.path.getsize(targetFile)
else:
exists = False
targetSize = 0
openMode: str
if exists:
openMode = 'br+'
else:
openMode = 'bw+'
with open(targetFile, openMode) as newfile:
if targetSize > 0:
header: str = f"blob {targetSize}\0"
headerBytes = header.encode('utf-8')
headBytesLen = len(headerBytes)
buffer = bytearray(headBytesLen + targetSize)
buffer[0:0+headBytesLen] = headerBytes
buffer[headBytesLen:headBytesLen+targetSize] = newfile.read()
sha1Hash = hashlib.sha1(buffer).hexdigest()
if not sha == sha1Hash:
newfile.truncate()
else:
continue
with requests.get(fullFile) as response2:
newfile.write(response2.content)
언급URL : https://stackoverflow.com/questions/7225313/how-does-git-compute-file-hashes
'programing' 카테고리의 다른 글
C# LINQ에 해당하는 Javascript 선택 (0) | 2023.08.16 |
---|---|
Rails 3 AJAX 원격 폼 콜백 (0) | 2023.08.16 |
모양 전환 시작/종료에 대한 불균형 호출 (0) | 2023.08.16 |
오류 jqxhr에 대한 Ajax GET URL (0) | 2023.08.16 |
$LastExitCode=0입니다만 $?= PowerShell에서 거짓.stdout으로 stderr을 리디렉션하면 Native CommandError가 발생함 (0) | 2023.08.11 |