안녕하세요!
프로그래밍을 해보신 분이라면 Git을 써보신 적이 있을 것 같아요.
늘 별 생각 없이 그냥 add, commit, push만 반복하였었지만 오늘은 이 Git이 내부에선 어떤 방식으로 우리의 파일들을 버전 관리하는지 정리해보려고 합니다.
Git의 구조
내 프로젝트를 파일관리 하기 위하여 `git init`을 입력하게 되면 .git 폴더라는 것이 생기는 것을 많은 분들이 알고 계실 것 같아요. 해당 폴더를 통해 버전이 관리되는데, 한번 들어가보면 아래와 같은 다양한 폴더와 파일들이 있습니다.
이 중 가장 핵심적인 부분으로는 index, objects 그리고 refs가 있습니다.
우선 구조를 먼저 생각해보자면 이런 느낌입니다.
아직 뭐가 뭔지 감이 안오죠? 하나씩 살펴보도록 하겠습니다.
index
먼저 버전관리를 위해 우리는 주로 `add`를 하게 됩니다. 이걸 저희는 스테이징이라고 부르죠. Git에서 스테이징을 하는 과정은 바로 index 파일에 내용을 채우는 과정입니다.
만일 a.txt라는 파일에 abc라는 문자열을 넣은 채로 git add a.txt를 입력했다고 가정해보겠습니다.
그럼 우선 Git은 a.txt파일의 내용을 hash처리합니다. 이 결과로 abc라는 문자열을 해시하니 aa1111111111라는 해시값이 나왔다고 가정해봅시다. 그럼 index라는 파일에는 aa1111111111 a.txt 이라는 한줄이 추가됩니다. 그리고 추가적으로 파일 모드와 파일 크기에 대한 정보도 추가됩니다.
a.txt에 abc, b.txt에 bcd가 있는 텍스트 2개를 add했을 때의 index 예시
12000 aa1111111111 12 a.txt
12000 bb2222222222 17 b.txt
------ ---------------- -------- -----
파일모드 해시코드 파일크기 파일명
Objects
Objects는 Git에서 버전관리에 사용될 모든 데이터가 저장되는 공간입니다. 그래서 한 종류의 파일이 있는 것이 아니라 다양한 종류의 파일들이 같은 형태로 Hash되어 저장되어 있습니다.
Blob
Objects 내에서 파일의 내용을 저장하는 객체입니다. 위의 예시를 이어가보자면 git add a.txt를 할 때 abc라는 문자열을 해시하여 aa1111111111라는 값을 도출했다고 했죠? 그렇게 되면 aa1111111111라는 경로에 문자열 abc를 저장합니다. 그리고 이 때 그냥 한 파일로 저장하지 않고 해시의 앞 두자리는 폴더명으로 하고 그 뒤는 파일명으로 하여 해당 파일에 파일의 내용(abc)를 저장하게 됩니다.
예시
여기까지 해서 git add 명령어를 진행할 때는 objects의 blob 파일과 index 파일을 생성하고 내용을 채웁니다.
Tree
이제 Commit할 때의 과정도 알아봅시다.
사용자가 파일이 현재 스테이징된 상태대로 커밋을 진행하게되며 우선 Objects폴더에서 Tree파일을 만들게 됩니다. 이 형식도 blob과 같이 해시값으로 폴더, 파일명을 지정하여 저장합니다.
Tree파일에는 index에 있는 내용과 거의 비슷한 내용을 저장하고 있으며, 이 내용들을 Hash처리하여 나온 값으로 폴더명, 파일명이 지정되어 objects 폴더 안에 저장됩니다.
예시
현재 상태에서 commit 때의 objects의 tree파일 예시
12000 aa1111111111 a.txt
12000 bb2222222222 b.txt
------ ---------------- -----
파일모드 해시코드 파일명
-> hash하여 tt3333333333가 나왔다면 objects/tt/3333333333파일에 저장됨
Commit
Tree 파일이 만들어지고 난 후 git commit 명령어의 마지막 단계로 objects 폴더에 commit이란 종류의 파일을 만듭니다.
이 commit 파일은 해당 commit을 한 정보를 담고있습니다.
해당 commit의 파일 구조를 담고 있는 tree의 hash값, 해당 commit의 부모 commit hash값, 작성자이름, 이메일, 커밋 메시지 등등의 내용을 갖고있습니다.
그리고 이 commit 파일 또한 예상했듯이 이 전체 내용을 hash처리하여 나온 값을 폴더명, 파일명으로 하여 objects 폴더에 저장합니다.
예시
commit 파일에 들어있는 내용
tree tt3333333333
author KIMB0B<axzsd96301@gmail.com>
feat: Add signup into user service
-> hash하여 cc4444444444가 나왔다면 objects/cc/4444444444파일에 저장됨
실제 Objects 구조 예시
아래 사진은 실제로 제 프로젝트의 .git에서 저장되어있는 Objects 폴더 내부의 구조입니다.
제가 물론 위의 예시에선 Hash처리한 값을 엄청 대충 입력하였지만, objects의 파일 구조는 파일을 Hash처리한 값의 앞 두자리는 폴더명, 나머지는 파일명으로 하여 각 파일들의 역할에 맞게 데이터를 저장하게 되어있습니다.
이런 구조로 되어있는 이유는 빠른 탐색입니다. 특정 해시값으로 가고 싶을 때, 우선 앞 2자리만 비교한 후 그 안에 있는 몇개 없는 파일들 사이에서 탐색을 진행하면 되니 효율적으로 탐색을 진행할 수 있습니다.
Refs
Refs 폴더는 말 그대로 reference 참조를 관리하는 디렉터리입니다. 주로 브랜치, 원격 저장소, 태그의 참조를 관리합니다.
관리한다는 말은 쉽게 얘기하자면 해당 브랜치 혹은 원격 저장소, 태그가 objects의 많은 commit들 중 어떤 commit을 가리키고 있는지 알려주는 하나의 포인터 역할을 합니다.
브랜치의 참조를 관리하는 예시를 보여드리기 위해 현재 프로젝트의 브랜치가 아래 이미지와 같은 상황일 대 Refs폴더는 어떤 모습일지 보여드리겠습니다.
예를 들기 위해 objects폴더를 바꿨습니다. 현재 Objects의 commit들은 아래와 같은 상황이고, blob과 tree까지 나타내기엔 너무 많고 불필요할 것 같아 저 두 종류의 object는 어딘가에 잘 있다고 생각하고 봐주시기 바랍니다.
보시다시피 objects 안에는 이렇게 폴더와 파일들이 주루룩 나열만 되어 있습니다. 그럼 이 commit들의 순서를 알게 해 주는 것은 바로 안에 있는 parent 부분입니다.
회색 점선 화살표를 보시면 해당 커밋이 이루어지기 이전 커밋의 해시값을 parent를 통해 알 수 있고, 이를 통해 이 바로 위에서 올린 현재 프로젝트 branch 상황을 유추할 수 있게 됩니다.
그럼 우리에게 남은 것은 각 브랜치에서 가장 마지막 커밋의 위치를 지정만 해주면 되는 것인데, 이걸 바로 refs에서 해줍니다.
refs에는 heads 폴더가 있고, 이 폴더에는 해당 프로젝트의 각 브랜치 이름과 같은 파일들이 하나씩 있습니다.
이 파일들을 열어보면 하나의 해시값만 덩그러니 적혀있는데요. 바로 이것이 해당 브랜치에서 현재 위치해있는 commit의 해시값입니다.
이 방법을 통해 여러 commit들 사이에서 여러 branch들을 관리할 수 있게 됩니다.
실제 refs 구조 예시
.git 폴더 안에 refs 폴더에는 위처럼 heads, remotes, tags 폴더가 있습니다.
각각 브랜치, 원격저장소, 태그의 commit 포인터를 가리키는 파일들이 있고, 가리키는 방식은 다 위에서 설명한 방식과 같습니다.
현재 제 프로젝트엔 main, develop, hotfix1, hotfix2라는 브랜치가 있어서 각 브랜치명으로 파일들이 있고, 저 파일 안에는 해당 브랜치가 위치하는 commit의 해시가 적혀있습니다.
마치며
git의 구조에 대해 알려고 생각해본 적이 사실 없었습니다.
하지만 구조를 알아보니 도움이 되는 내용이 생각보다도 훨씬 많았습니다.
파일의 변동을 확인하기 위해 hash값의 변화를 본다던가, 탐색을 빠르게 하기 위해 앞 2자리를 폴더명으로 우선 저장해놓는다던가, blob/tree/commit 이 3개의 다른 데이터가 들어가는 파일을 한 폴더에 몰아넣어도 서로 유기적으로 잘 동작하게 설계해놓는 등 앞으로 내가 개발을 통해 만들어나갈 것에 꽤나 큰 영감이 될만한 내용들이 많았습니다.
'부스트캠프 9기 > 챌린지' 카테고리의 다른 글
[부스트캠프 9기 챌린지] 학습 정리 - 16일차 (0) | 2024.08.05 |
---|---|
[부스트캠프 9기 챌린지] 회고 - 2주차&3주차 (0) | 2024.08.03 |
[부스트캠프 9기 챌린지] 학습 정리 - 11일차 (0) | 2024.07.29 |
[부스트캠프 9기 챌린지] 학습 정리 - 09일차 (0) | 2024.07.25 |
[부스트캠프 9기 챌린지] 학습 정리 - 08일차 (0) | 2024.07.24 |