
Git은 Content-addressable 파일시스템
Git의 핵심은 단순한 Key-Value(ex, 파일 이름과 파일 데이터) 데이터 저장소라는 것
git hash-object라는 한 Plumbing 명령어가 존재
이 명령에 데이터를 주면 .git/objects 디렉토리에 저장하고 그 데이터에 접근할 수 있는 key를 알려주며 이 key는 저장소 내에서 유일함
git init 명령어로 새로운 Git 저장소를 만들면 objects 디렉토리에는 당연히 아직 아무 것도 없음

Git은 init 명령으로 저장소를 초기화할 때 objects 디렉토리를 생성하고 그 밑에 pack 과 info 디렉토리도 생성
git hash-object 명령을 사용하여 Git 데이터베이스에 새 데이터 개체를 직접 저장해보면,

위와 같이 -w 옵션을 줘야 실제로 저장, —stdin 옵션을 주면 표준 입력으로 입력되는 데이터를 읽음(—stdin을 사용하지 않으려면 파일 경로를 지정해줘야 함)
그러면 결과로 이 데이터에 접근하기 위한 40자 길이의 체크섬 해시의 key를 반환

find 명령어로 파일을 찾아보니 objects 디렉토리에 파일이 하나 생성됨
데이터는 새로 만든 파일에 저장하며 Git은 데이터를 저장할 때 데이터와 헤더로 생성한 SHA-1 체크섬으로 파일 이름을 지음
해시의 첫 두 글자(위의 d6)을 디렉토리 이름으로, 나머지 38글자를 파일 이름으로 사용
Git 데이터베이스에 개체를 저장하고 나면 이후에는 git cat-file 명령으로 저장한 데이터를 불러올 수 있음

-p 옵션을 붙이고 40글자의 해시를 검색하면 위와 같이 파일의 내용을 출력

이렇게 test.txt을 생성하고 저장 후, 수정을 한 뒤에 다시 저장하면 위처럼 .git/objects에 새로운 파일 두 개가 추가됨
이제 test.txt를 지우더라도 Git을 사용하여 test.txt 파일을 두 버전 모두로 되돌릴 수 있음


이렇게 해시 이름을 가지고 생성되는 종류의 개체를 Blob 개체라고 부름
아래와 같이 git cat-file -t 명령으로 SHA-1 key를 입력하면 가리키는 해당 개체가 무슨 개체인지 확인할 수 있음

Tree 개체에 파일 이름을 저장
파일 여러 개를 한꺼번에 저장할 수도 있음
Git은 모든 것을 Tree와 Blob 개체로 저장함
Tree는 유직스의 디렉토리와 대응하고 Blob은 Inode나 일반 파일에 대응
Tree 개체 하나는 여러 항목을 가질 수 있으며, 이 항목은 Blob 개체나 하위 Tree 개체를 가리키는 SHA-1 포인터, 파일 모드, 개체 타입, 파일 이름이 들어 있음
Git은 일반적으로 Staging Area(Index)의 상태대로 Tree 개체를 만들고 기록
그래서 Tree 개체를 만들려면 우선 Staging Area에 파일을 추가해서 Index를 만들어야 함
Plumbing 명령인 update-index 명령으로 test.txt 파일만 들어 있는 Index를 만들 수 있음
아직 Staging Area에 없는 파일이기 때문에 --add 옵션을 줘야 함
그리고 디렉토리에 있는 파일이 아니라 데이터베이스에 있는 파일을 추가하는 것이기 때문에 --cacheinfo 옵션이 필요
파일 모드, SHA-1 해시, 파일 이름 정보도 입력

위는 직접 Tree 개체를 만드는 과정
100644는 보통의 파일 모드 (실행 파일이라면 100755, 심볼릭 링크라면 120000으로 지정)
git update-index 명령어로 Staging Area에 올린 후 git write-tree 명령어로 Tree 개체로 저장하는 것

tree 개체임을 확인할 수 있음

이 사진과 같이 Tree를 하위 디렉토리로 만들 수 있음
처음의 Tree 개체를 git read-tree —prefix=bak {tree 해시값} 명령어로 Tree 개체를 읽어 Staging Area에 추가
Tree 개체로 워킹 디렉토리를 만들면 파일 두 개와 bak 이라는 하위 디렉토리가 생김
그리고 bak 디렉토리 안에는 test.txt 파일의 처음 버전이 들어 있음
위와 그림과 같은 구조로 데이터가 저장
Tree 개체를 만들어 스냅샷을 불러오려면 SHA-1 값을 기억하고 있어야 함
스냅샷을 누가, 언제, 왜 저장했는지에 대한 정보 또한 존재하지 않음
이러한 정보를 저장하는 것이 커밋 개체
커밋 개체는 commit-tree 명령으로 만들 수 있음

git commit-tree {tree SHA-1값} 명령어로 tree 개체를 ‘first commit’이란 내용을 담아 커밋 개체를 생성하였다.

커밋 개체의 형식은 해당 스냅샷에서 최상단 Tree를 하나 가리키고 Author/Commiter 정보와 시간 정보, 한 줄 띄고 커밋 메세지의 형식을 가진다.
만들었던 tree로 새로운 2개의 커밋을 생성
각 커밋 개체는 전에 만든 커밋을 가리키도록 설정

그 후 git log --stat 82323f(마지막 커밋 SHA-1값)를 입력하니 지금까지의 커밋 로그가 찍힘

지금 한 일이 git add 와 git commit 명령을 실행했을 때 Git 내부에서 일어나는 일
Git은 변경된 파일을 Blob 개체로 저장하고 현 Index에 따라서 Tree 개체를 생성
그리고 이전 커밋 개체와 최상위 Tree 개체를 참고해서 커밋 개체를 생성
Blob, Tree, 커밋 개체가 Git의 주요 개체이고 이 개체는 전부 .git/objects 디렉토리에 저장
지금까지 만들어진 개체들은 다음과 같음

내부의 포인터를 따라가면 아래와 같은 그림이 그려짐
