Section 18: Git의 이면 -해싱(Hashing)과 객체

김남훈·2024년 2월 3일

Git & Github

목록 보기
16/18

Critical

Important

The Local Config File

config 파일은 설정을 위한 파일로 모든 저장소에 존재한다. 이 파일에 값을 설정한다면 이 값은 현 저장소에서만 유효하고 다른 저장소에는 영향이 없다. 그러나 설정 값을 바꿀 때는 많이 없을 것이다. 예전에 사용했던 명령어인 git config user.name 과 같은 명령어는 전역적으로 설정을 바꾸지만 git config --local user.name을 하면 지역적으로 설정을 바꾼다.

참고적으로 색을 바꾸는 방법을 알아보겠다. config파일을 다음과 같이 바꾼다.

Nice To Have

The Refs Directory

이 폴더 안에 하위 폴더 두어개가 있는데 그 중에 heads 폴더를 살펴보자. 깃은 이 refs/heads 디렉토리 안에 저장소에 존재하는 브래니 마다 파일을 하나씩 만든다. 예를 들어서 Darkmode라는 브랜치가 있다면 Darkmode라는 파일이 있다. 그 파일 각각 커밋 해쉬가 저장 되어있다.

The HEAD File

HEAD 파일을 열어보면 ref: refs/heads/main 라고 나와있다. 이는 HEAD가 가리키고 있는 브랜치 레퍼런스를 뜻한다.

Hashing Functions Basics

깃에 대해 알아보기 전에 해시 함수에 대해 알아보겠다. 해쉬번호는 40개의 16진수로 이루어져 있다. 이것은 해시 함수의 결과물이다. 해시 함수는 하나의 목적을 가진 함수이다. 작든지 크든지 다양한 크기의 값을 입력 받고, 고정된 길이의 값을 출력한다. 입력값이 파일일 수도, 한 자리 숫자일수 도 있는데, 출력값의 길이는 고정되어있다. 이 함수는 동일한 입력값에 대해서는 결과는 항상 같아야 한다. 또 다른 특징은 일방 함수여야 한다. 즉 출력값으로 입력값을 알 수 없어야 한다. 만약에 비밀번호가 서버에 해쉬값으로 저장되어있다면, 해커가 데이터베이스에 접근해서 해쉬된 암호값에 접근한다고 해도 이를 해석하기 불가능해야 한다. 그리고 입력값에 작은 변화가 생기면 출력값에 큰 변화가 생겨야한다. 다른 두 입력값에서 같은 출력값이 나올 확률이 극히 낮아야 한다. 깃은 SHA-1라는 해쉬 함수를 사용한다. SHA-1는 꽤 오래된 해쉬함수로 항상 40자리 16진수 문자열을 생성한다.

Git Objects: Blobs, Trees and more!

git의 핵심이라고 할 수 있는 것이다. .git 디렉토리 안에 objects 폴더가 있다. 그 안에 많은 서브 폴더가 있다. 폴더 이름은 두개의 16진수로 되어있고 안에 파일이 있다. 안의 파일은 바이너리 파일이다. 이 오브젝트 디렉토리 안에는 레포지토리의 모든 정보가 담겨져 있다. 이 오브젝트 폴더 안에는 네 종류의 깃 객체가 들어갈 수 있다. 각각 commit, tree, blob ,annotated tag 이다. 이 네 개 모두 SHA-1으로 해쉬된 값을 담는다.
깃은 key-vale data store로 우리가 깃 리포지토리에 컨텐츠를 저장하면 깃은 우리에게 키를 주고 우리는 나중에 그 컨텐츠를 다시 가져오기 위해 그 키를 사용한다. 이 키들은 SHA-1 checksum 즉 SHA-1 해싱 함수의 출력값이다. 아래의 그림을 보자.

그래서 이 키를 가지고 깃에 해당 콘텐츠를 달라고 요청하면 깃은 키를 활용해서 values를 알려준다.

깃 오브젝트 폴더 안에 폴더를 보면 ce가 폴더명이고 그 안에 그 다음 해쉬 값이 파일명으로 나타나있다. 즉 해쉬의 앞 두글자는 폴더명이되고 뒤에 38글자는 그 폴더 안에 파일명이 된다. 그 파일안에는 실제로 컨텐츠가 포함되어 있고 이 경우에는 헬로로 되어 바이너리로 저장되어 있다.

git cat-file -p <object-hash> 는 저장한 데이터를 가지 꺼내는 것이다. 깃의 해쉬는 반드시 깃 객체와 연결되어있다. 네 종류의 깃 객체 중 하나(commit, tree, blob, annotated tag)와 연결되어있다.

Blobs (Binary Large Object)

깃이 저장할 수 있는 객체 중 한 종류로, 블롭은 파일 내용을 저장하는 객체이다. 파일이 담고 있는 내용 그 자체이다. 파일 내용만을 포함한다(제목도 포함하지 않는다). 깃은 파일 이름과 내용을 분리해서 저장한다.

Trees

디렉토리 내용을 저장한다. 따라서 트리는 블롭을 가리키는 포인터와 트리를 가리키는 포인터 둘 다 가지고 있다. 예를 들어 폴더가 하나 있고 그 안에 파일이 하나 있다고 해보자. 트리 안에는 블롭을 가리키는 포인터가 있고 트리를 가리키는 포인터가 있다.

git cat-file -p master^{tree} 로 트리 내용을 볼 수 있다.

Commits

커밋을 생성하면 깃은 커밋 객체를 생성해서 저장한다. 블롭이나 트리 같은 깃 객체를 저장하듯이 커밋 객체도 저장이 된다. 커밋 객체는 부모 커밋을 가리키는 값이 있는데, 이는 깃 저장소에 존재하는 히스토리를 얻기 위함이다. 또한 커밋은 트리 오브젝트를 참조한다. 아래의 그림을 확인하자.

git commit을 실행하면 깃은 커밋 객체를 생성하고 현재 HEAD가 가리키는 커밋을 부모로 설정한다. 그리고 스테이징 영역(index)에 있는 현재 상태를 기반으로 새로운 트리를 만들어 커밋 객체에 포함시킨다. 트리는 해당 애플리케이션의 구조를 보여주고 파일 내용을 담고있는 블롭까지 보여주게 된다. 예를 들어서 커밋을 체크아웃하거나 커밋을 기반으로 브랜치를 생성하면 깃은 해당 커밋의 트리를 토대로 워킹 디렉토리를 구성한다.

실제로 커밋 내용이 있는 바이너리 파일을 git cat-file -p <commit hash>를 해보면, 다음과 같이 나온다.

profile
안녕하세요

0개의 댓글