Git
깃,,, 지금까지 무지성으로 add, commit, push하고, 문제가 생기면 reset, revert, log정도 써왔던 버전관리 시스템이다.
이번 기회에 내부를 한번 뜯어보자.
Git init
git init을 하면 .git 파일이 생긴다.
이 녀석의 내부는 이렇게 생겼다.
깃은 Blob, Tree, Commit 이 세가지로 상태를 추적하고 관리한다. 어떻게 파일 버전을 관리하는지 흐름을 살펴보며 세가지 오브젝트를 살펴보자.
Blob
Git의 파일 상태 저장 방법
깃에서 파일상태를 저장하는 방법을 요약하면 이렇다.
1. 코드가 있는 파일을 전부읽는다.
2. 하나의 파일마다 그 내용에 대해 해시해서 파일 제목을 만든다. (해시값은 유일하므로, 겹칠 수 없다.)
3. 파일의 내용으로는 원본 파일의 내용을 zlib으로 압축한 이진형태의 데이터를 기록한다.
지금까지 과정을 그림으로 보면 아래와 같다.
근데 이걸 objects파일 내부에 그냥 파일로 저장하는게 아니고, 해시첫 두글자를 딴 디렉토리를 만들고, 나머지 해시를 제목으로 해서 파일을 넣는다.
이렇게 하는 이유는 하나의 디렉터리에 너무 많은 파일이 있으면 성능이 저하되기때문이라고 한다.
따라서 파일 저장방식의 실제작동은 아래와 같다.
이렇게 만들어진 파일을 Blob(binary large object)이라 한다.
하나의 파일당 하나의 Blob이 생성된다.
이렇게 저장한 파일은 해당 디렉터리+파일명에 해당하는 해시값으로 그 내용을 확인할 수 있다.
이는 모든 오브젝트에 대해 가능해서, Tree나 Commit객체를 확인할때도 사용가능하다.
git cat-file -p <해시값>
Tree
근데 우리는 디렉터리를 관리하는데?
Blob을 관리해줄 녀석이 필요하다. 이게 바로 Tree이다.
트리는 Blob의 목록을 관리한다.
트리 객체는 커밋을 수행할때 생성된다.
a.txt를 만들고, add -> commit을 했다고 하면, .git/objects파일 내부에 blob파일과 blob정보를 기록한 tree, 그리고 commit오브젝트가 들어있게 된다.
그중 tree객체를 열어보자.
모든 해시가 어떤값인지는 알아내기 불가능하므로.... 하나씩 찾아봐야한다.
아래 명령어로 해당 해시값이 어떤 오브젝트인지 타입을 얻을 수 있다.
git cast-file -t 해시값
tree라고 출력된다면 아래의 명령어를 수행시키자.
git cat-file -p 해시값
100644 | 파일의 권한 (100644 : 일반파일이라는 뜻) |
blob | 파일의 유형 |
391154f... | 해시값 |
a.txt | 파일이름 |
디렉터리가 중첩되어 있는 경우는?
루트폴더내에 src라는 폴더를 만들고 a.txt를 저장했다고 하자.
그러면 루트트리에 해당하는 오브젝트 해시값을 확인하면 아래와 같이 나온다.
100644, 040000 | 파일의 권한 (100644 : 일반파일이라는 뜻 040000 : 트리 오브젝트) |
blob, tree | 파일의 유형 |
391154f... | 해시값 |
a.txt, src | 파일이름, 폴더이름 |
이처럼 트리에 트리를 넣어서 중첩적인 디렉터리를 처리하는 것이다.
이렇게 하여 트리는 특정 순간의 스냅샷을 기록하게 된다.
그럼 이 스냅샷을 관리해주는 친구도 필요할 것이다.
그게 바로 커밋이다.
Commit
커밋오브젝트는 git commit 명령어가 수행됐을때 만들어진다. 트리와 블롭객체와 마찬가지로 objects 디렉토리에 저장된다.
커밋은 트리를 관리해준다. 스냅샷과 스냅샷을 이어주는 역할을 하는 것이다.
커밋은 현재 트리와 이전 커밋을 기록한다. 그리고 기록자와 커밋 메시지를 기록한다.
tree fba2ec34.... | 현재 트리값 |
parent a3467b.... | 이전 커밋값 |
author d0422..., committer d0422... | 작성자 |
hello | 커밋 메시지 |
복원
git을 사용하는 가장 큰 이유들중 하나는 특정 시점으로 파일버전이 복구가 가능하기 때문일 것이다.
이것이 어떻게 가능한지 순서대로 간단하게 살펴보자.
1. git reset 해시값으로 특정 커밋으로 이동시도
2. .git/objects 내부에서 해당 해시값으로 커밋오브젝트 파일 찾기
3. 커밋오브젝트에서 현재 트리 오브젝트의 해시값 찾기
4. .git/objects 내부에서 해당 트리 해시값으로 트리 오브젝트 찾기
5. .git/objects 내부에서 트리에서 관리하는 blob오브젝트들 찾기
6. 각 blob오브젝트에 대한 압축해제, 원본 내용 획득
7. 현재 디렉토리로 복원