
분산 버전 관리 시스템(Distributed Version Control System, DVCS)은 소스 코드와 히스토리를 중앙 서버뿐만 아니라 사용자의 로컬 저장소에서도 완전한 복사본으로 저장하는 방식입니다. 이점은 로컬에도 복사본이 있기 때문에 중앙 서버의 의존도를 줄일 수 있고, 개발자들이 로컬에서 독립적으로 작업하고 변경 사항을 저장할 수 있다는 것입니다.
DVCS의 예시는 Git, Mercurial, Bazzar, Fossil과 같은 예시가 있지만 이 중 git에 대해서 알아보겠습니다.
Git은 모든 데이터를 파일 형태로 저장합니다. Git의 개발자인 리누스 토르발스는 리눅스의 개발자이기도 합니다. 리눅스와 Git은 모두 파일 시스템의 특성을 활용합니다. 둘 다 트리 구조와 계층적 관리를 합니다. Git은 다음과 같이 Git objects를 만들어 계층적으로 관리를 합니다.
blob: 파일의 콘텐츠를 저장하는데 사용합니다. 파일의 메타 데이터는 없으며 오직 파일의 내용만 압축하여 저장하고 해당 압축 파일을 SHA-1 해시화 하여 이름으로 지정합니다.
tree: 디렉토리 구조를 나타내는 객체입니다. tree는 blob과 다른 tree에 대한 포인터를 포함하여 디렉토리 내의 파일과 하위 디렉토리를 나타냅니다.
commit: root tree에 대한 포인터, 부모 commit에 대한 포인터, 작성자, commit message 등을 포함합니다.
tag: 특정 commit에 대한 참조를 추가적인 메타데이터와 함께 저장하는 객체입니다. 주석 태그와 경량 태그로 나뉘며 주석 태그는 태그 이름, 설명, 태그를 만든 사람 등이 포함되며 경량 태그는 특정 커밋을 가리키는 포인터입니다.
먼저 init 명령어를 통해 .git 폴더가 만들어지며 하위에 여러 폴더와 파일이 생기는데 이 중 objects 폴더에 앞서 말했던 객체들이 들어가게 됩니다.
add 명령어를 실행하면 add한 파일에 대해서 내용을 압축을 하여 SHA-1 해시화합니다. 나온 해시값의 두 글자는 폴더 이름, 나머지는 파일 이름으로 objects 폴더 밑에 저장합니다. 그리고 index 파일 안에 해당 파일에 대한 파일모드(종류, 권한)와 해시값, 파일 이름이 저장됩니다.

이후 commit 명령어가 들어오면 index 파일을 참고해서 tree 객체를 만들게 됩니다. tree 객체는 index 파일과 비슷하게 파일 모드, 해시값, 파일 이름에 대한 정보를 개행 단위로 저장합니다. 만일 폴더의 깊이가 2개 이상이라면 폴더 레벨당 하나씩 tree를 만들게 됩니다. 그 뜻은 tree 안에 tree 포인터가 들어가게 됩니다. 그리고 커밋 객체를 만들게 되는데, root tree와 부모 커밋과 작성자, 커밋 메시지를 넣어서 저장하게 됩니다.


앞선 add 프로세스에서 파일 내용을 압축하여 해시 값을 뽑는데, 같은 파일의 내용일 경우 파일 이름이 달라도 같은 해시 값을 가지기 때문에 index 파일에 기록할 때 같은 포인터를 가리키게 됩니다.