Github에 계속 작업을 하다보니 한번 정리해보면 좋겠다는 생각에 작성합니다.
본 필자는 Mac 환경에서 작업하고 있음을 알립니다.
우리는 프로젝트 협업에서
git을 많이 사용하고 있습니다.
그럼git은 버전관리도구일까요? 협업툴일까요?
정답은git자체는 버전관리도구이며,github를 통해 소스코드를 주고받거나
브랜치를 통해 공유하는 협업툴입니다.
git은 커밋마다 각각의 소스코드를 가지고 있습니다.
그리고 브랜치마다 다른 소스코드를 가지고 있습니다.
그렇다면 방대한 양의 코드를 어딘가에 저장하고 있다는 소리입니다.
근데 이러한 백업코드를 가지고 있다면 프로젝트 파일이 거대할 것 같은데
실상은 그렇지 않습니다.
작은 양의 크기로 이러한 모든 정보를 가지고 있는 것입니다.

git을 창시한 리누즈 토발즈가 git에 최초 커밋을 하며 함께 작성한
README파일 중 일부에는"git은 멍청한 버전 관리기"라고 칭했습니다.
그만큼 멍청하고, 한심한 git의 내부구조를 알아봅시다.
git을 사용하기 위해서는 프로젝트의 루트 디렉토리 위치에서 git을 초기화 해줍니다.
git을 초기화한 프로젝트는 .git이라는 숨김 디렉토리가 생성된다는 것을 알 것입니다.
git에서 스테이징과 커밋이라는 행위는 object -> 객체로 저장됩니다.
git의 가장 주요 세 가지 객체는blob,tree,commit입니다.

우리는 코드를 작성하고 나서 해당 코드를 커밋하기 위해서는
먼저 스테이징을 해야 합니다.
git은 git add 명령어를 통해 스테이징을 하면 변경된 파일의 변경사항을
blob 오브젝트라는 객체로 .git 하위 디렉토리인 objects 디렉토리에 추가하게 됩니다.

bolb 오브젝트는 변경된 내용을 기반으로 하여 디렉토리 그리고 하나의 파일로 구성됩니다.
변경된 내용을 기반으로 sha-1 해시 암호화를 통해 40글자의 체크섬 문자열을 만들어서
앞의 두 글자는 디렉토리가 나머지 글자는 파일 이름으로 저장됩니다.
여기서 git은 어떤 데이터든지 데이터를 저장하기 전에 항상 체크섬을 구하고,
체크섬을 기준으로 모든 데이터를 관리합니다.
이것이 git의 스테이징 원리입니다.

보통의 프로젝트는 여러 디렉토리로 구성됩니다.
파일 말고도 디렉토리가 생성될 수도 삭제될 수도 있습니다.
이렇게 새롭게 생성되거나 삭제되는 디렉토리 정보를 tree 오브젝트에서 만듭니다.
tree오브젝트는 하위 파일의 변경사항인 blob 오브젝트의 변경사항을 기반으로 한
체크섬 또는 tree 오브젝트의 변경사항을 기반으로 한 체크섬을 갖고 있습니다.
쉽게 설명하면 스냅 샷을 비유할 수 있는데
트리에는 커밋을 한 순간 스테이지에 있는 작업파일들의 ID뿐만 아닌 실제 파일이름,
어느 디렉토리에 속해있는지 전체 관계도가 담겨 있습니다.
이러한 스테이징 변경 사항을 통해 하나의 커밋을 만들게 됩니다.
이것이 commit 오브젝트입니다.
commit오브젝트는 이전 commit 오브젝트와
가장 상단의 루트 tree 오브젝트를 참조한 체크섬으로 구성됩니다.
commit마다 가르키는 최고 상단의 tree 오브젝트를 가르키면서
git은 모든 변경사항을 객체를 통해 저장하고 있는 것입니다.
예를 들면 폴라로이드 사진을 앨범에 붙이고 나면 언제 찍은 것인지 확인하게 되는데
메모한 것이 커밋의 역할이라고 생각하면 됩니다.
즉 트리의 ID, 저자와 Committer, 부모 커밋의 ID, 커밋 메시지를 담게 됩니다.
commit 객체(Key=Value)를 살펴보면
- 레포지토리의 루트 디렉터리에서 tree 객체의 해시 값(key)
- 상위 commit 해시 값
- committer와 author 타임 스탬프, 이름, 이메일 주소
- 커밋 메시지
이 중 하나라도 변경하면 다른 commit 해시가 되므로 커밋은 고유하게 관리가 됩니다.
또한 부모 커밋의 해시도 포함하고 있기 때문에 병합 충돌이 일어나는 것입니다.
blob는 파일 정보가 들어 있는 객체
tree는 디렉토리 정보가 들어 있는 객체
commit은 커밋 정보가 들어 있는 객체
결국 커밋이 있고 그것을 올라가면 브랜치가 있고 브랜치는 커밋을 가르키고 있는 것입니다.