git을 사용하면서 동작하는 원리가 궁금할 때가 있었다. git의 원리를 제대로 이해하지 못하고 명령어만 사용한다면 실수할 확률이 높고 이해도 잘 안 되어 명령어를 잊어버리기 쉽다. 만약 git이 어떤 식으로 파일을 관리하고 동작하는지 이해한다면 git을 사용할 때 훨씬 더 자유롭게 사용할 수 있고 실수할 확률이 줄어든다. git의 동작을 파악하기 위해 git repository에 필수적으로 존재하는. git 디렉터리를 살펴보고 어떤 식으로 동작하는지 공부해 본다.
여러 블로그들을 보았지만 아래 블로그가 정리가 잘되어 있어서 참고했다.
https://it-eldorado.tistory.com/4
. git 안에는 무엇이 있고 어떻게 동작할까
- . git 디렉터리 구조 파악
- git 동작 파악
. git 디렉터리 구조 파악
아래는. git 내부에 존재하는 것들을 tree로 표시하도록 한 것이다.
├── COMMIT_EDITMSG
├── FETCH_HEAD
├── HEAD
├── ORIG_HEAD
├── branches
├── config
├── description
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ └── update.sample
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ ├── heads
│ │ └── master
│ └── remotes
│ ├── origin
│ │ └── HEAD
│ └── upstream
│ ├── master
│ └── release
├── objects
│ ├── 18
│ │ └── 511b953a1a3fe957b1a5badd7a5bacc2dc9db3
│ ├── 6c
│ │ └── a0c5648cc79f17fb1b9d9207ef835c5fa94213
│ ├── d5
│ │ └── c121c40ecc2aca1fd8010ff29c91b551d16a22
│ ├── info
│ └── pack
│ ├── pack-610814ad79609d873aaf02870ed39b0b499c2308.idx
│ ├── pack-610814ad79609d873aaf02870ed39b0b499c2308.pack
│ ├── pack-7e63ffdce12f9e8efe4b888dfe65e6d4474271f2.idx
│ └── pack-7e63ffdce12f9e8efe4b888dfe65e6d4474271f2.pack
├── packed-refs
└── refs
├── heads
│ └── master
├── remotes
│ ├── origin
│ │ └── HEAD
│ └── upstream
│ ├── master
│ └── release
└── tags
├── v2.8.0
├── v2.8.1
├── v2.8.10
잘 정리되어 있는 그림이 있어서 참조하였다. 이 그림 하나로 많은 것들이 정리가 된다.
주요 3가지 개념
개념 | 실제 위치 | 설명 |
Working Directory |
프로젝트 폴더 |
현재 수정하거나 추가하는 파일에 해당 하는 공간이다. |
Index = Staging Area |
프로젝트 폴더 하위 .git/index 파일 |
개념적으로는 커밋이 이뤄질 준비가 된 파일의 내용들이 위치하는 영역을 의미하며, 실제로는 하나의 파일(.git/index)로서 존재한다. 로컬에 변동 사항이 생겼을 경우, git add 명령어를 수행하면 해당 변동 사항을 인덱스 영역에 반영시킬 수 있다. 참고로, 인덱스 파일(.git/index)에는 커밋이 이뤄질 준비가 된 파일의 내용들 각각에 대하여 그 파일명과 해당 파일의 내용을 담고 있는 Blob 파일의 주소(이름)가 기록된다. |
Repository | 프로젝트 폴더 하위 .git/objects/ 폴더 |
깃이 버전 관리를 하기 위해 필요로 하는 데이터들을 저장하는 곳이다. 대표적으로, 버전 관리를 시작한 시점부터 현재 시점까지 관리해온 여러 버전들에 해당하는 파일들의 내용이 Blob 파일로서 이곳에 저장되어 있다. 이곳에 저장된 파일들을 특별히 오브젝트 파일이라고 부르며, Blob 파일도 오브젝트 파일의 한 종류이다. |
오브젝트 파일
오브젝트 파일이란. git/objects/ 폴더에 존재하는 파일을 가리키며, 다음과 같이 분류된다.
종류 | 설명 |
Blob 파일 | 버전 관리하는 파일들 각각의 내용은 깃의 저장소에서 Blob 파일의 형태로 저장된다. 파일의 내용에 SHA1이라는 해싱 기법을 적용하여 Blob 파일의 이름을 얻어내기 때문에, 내용이 같은 파일들은 모두 하나의 Blob 파일로서 저장된다. 이러한 원리로 깃은 여러 버전에 걸쳐 존재하는 파일들의 내용을 중복 없이 관리할 수 있게 된다. |
Commit 파일 | 하나의 버전을 생성한다는 것은 하나의 Commit 파일을 만드는 것을 의미한다. Commit 파일은 하나의 Tree 파일을 가리키게 되어 있다. 이 파일에는 가리키고 있는 Tree 파일의 주소(이름)와 직전 버전에 해당하는 Commit 파일의 주소(이름)가 기록된다. |
Tree 파일 | 커밋 시점의 파일들 각각에 대해 그 파일명과 해당 파일의 내용을 담고 있는 Blob 파일의 주소(이름)가 기록된다. 위에서 설명했던 인덱스 파일(.git/index)과 성격이 유사하다. |
HEAD와 브랜치 포인터
명칭 | 실제 위치 | 설명 |
HEAD | .git/HEAD | 현재 체크아웃되어 있는 브랜치의 포인터를 가리키는 포인터이다. 브랜치의 포인터가 아닌 일반적인 Commit 파일을 가리키게 할 수도 있다(이러한 경우를 detached HEAD라고 표현한다). |
브랜치 포인터 | .git/refs/heads/{브랜치명} | 해당 브랜치의 가장 최신 Commit 파일을 가리키는 포인터이다. |
HEAD와 브랜치 포인터의 히스토리
실제 위치 | 설명 |
ORIG_HEAD | HEAD 값의 변화를 기록한 것으로, 위험한 명령(EX. git reset)을 수행하기 직전의 커밋을 조사하기에 유용하다. |
.git/logs/refs/heads/{브랜치명} | 해당 브랜치의 포인터가 어떤 명령에 의해 어떻게 바뀌었는지를 기록한 파일 |
결론
Git을 사용하면서 원리를 어느 정도 이해하고 나니 git add, git commit 등의 명령어를 수행함에 따라 Git이 어떻게 변하는지 대략적으로 감을 잡을 수 있었다. GUI로 활용하던 CLI 입력으로 Git을 사용하던 원리를 이해하면 훨씬 더 자유롭고 생산성 있게 Git을 활용할 수 있는 것 같다.
반응형
'개발 > Git' 카테고리의 다른 글
[Git] .gitignore를 설정해서 불필요한 파일 무시하기 (0) | 2023.02.06 |
---|---|
[Git] GitHub fork와 upstream을 활용한 안전한 Pull Request (0) | 2023.02.04 |
[Git] Rebase와 Merge의 차이 by Visualizing-git (0) | 2023.02.02 |
[Git] 안심하고 commit하자 reflog (0) | 2023.01.13 |
[Git] 자주 쓰는 명령어, 익숙해지자 (0) | 2023.01.13 |