.git 폴더 안에 뭐가 있을까?
Source: Dev.to
.git 폴더 안에 뭐가 있을까?
Git은 모든 버전 관리 정보를 .git 디렉터리 안에 저장합니다. 이 폴더를 살펴보면 Git이 어떻게 작동하는지 이해하는 데 도움이 되는 여러 파일과 서브디렉터리를 볼 수 있습니다. 아래에서는 가장 흔히 마주치는 항목들을 하나씩 살펴보겠습니다.
주요 디렉터리와 파일
| 경로 | 설명 |
|---|---|
objects/ | 실제 커밋, 트리, 블롭, 태그 객체가 저장되는 곳. 객체는 SHA‑1 해시값을 파일명으로 사용하며, 두 단계의 디렉터리 구조(aa/bbbbb…)로 나뉩니다. |
refs/ | 브랜치와 태그에 대한 포인터가 들어 있습니다. - refs/heads/ : 로컬 브랜치 - refs/remotes/ : 원격 트래킹 브랜치 - refs/tags/ : 태그 |
HEAD | 현재 체크아웃된 브랜치를 가리키는 심볼릭 레퍼런스. 보통 ref: refs/heads/main 형태입니다. |
config | 저장소 수준 설정 파일. 사용자 이름, 이메일, 원격 URL, 병합 전략 등 다양한 옵션이 들어 있습니다. |
index | 스테이징 영역(인덱스) 정보를 담고 있는 바이너리 파일. 작업 디렉터리와 커밋 사이의 중간 상태를 기록합니다. |
logs/ | 레퍼런스 변경 이력을 기록합니다. - logs/HEAD : HEAD가 이동한 기록 - logs/refs/heads/* : 각 브랜치의 업데이트 로그 |
info/ | 전역 무시 파일(exclude) 등 보조 정보를 저장합니다. |
packed-refs | 많은 레퍼런스가 있을 때 하나의 파일에 압축 저장합니다. |
description (옵션) | Git 웹 인터페이스(Gitweb, cgit 등)에서 저장소 설명을 표시할 때 사용됩니다. |
hooks/ | 커밋, 푸시, 머지 등 다양한 이벤트에 대한 스크립트를 넣을 수 있는 디렉터리. 기본적으로는 샘플 스크립트가 .sample 확장자로 제공됩니다. |
COMMIT_EDITMSG, MERGE_MSG, MERGE_HEAD 등 | 현재 진행 중인 커밋 메시지, 병합 상태 등을 임시로 저장하는 파일들. |
객체(objects/) 구조 자세히 보기
- 블롭(blob) : 파일 내용 자체를 저장합니다. 파일 이름이나 메타데이터는 포함되지 않으며, 내용만 SHA‑1 해시로 식별됩니다.
- 트리(tree) : 디렉터리 구조를 나타냅니다. 트리 객체는 블롭과 다른 트리(서브디렉터리)의 레퍼런스를 포함합니다.
- 커밋(commit) : 트리 객체와 부모 커밋(들), 저자·커밋터 정보, 커밋 메시지를 포함합니다.
- 태그(tag) : 특정 커밋이나 객체에 대한 고정된 레퍼런스를 제공하며, 서명된(tag -s) 형태도 가능합니다.
객체 파일은 두 단계 디렉터리 구조를 가집니다. 예를 들어, SHA‑1 해시가 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391이라면 실제 파일 경로는 objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391이 됩니다.
HEAD와 refs의 관계
HEAD는 현재 체크아웃된 브랜치를 가리키는 심볼릭 레퍼런스입니다.HEAD가 가리키는 브랜치는refs/heads/아래에 실제 파일로 존재합니다. 예:refs/heads/main파일 안에 최신 커밋 SHA‑1이 들어 있습니다.git checkout <branch>를 실행하면HEAD파일이 새로운 브랜치를 가리키도록 업데이트됩니다.
index(스테이징 영역)
git add를 실행하면 파일의 현재 상태가 인덱스에 기록됩니다. 인덱스는 작업 디렉터리와 마지막 커밋 사이의 차이를 추적하며, git commit 시점에 인덱스에 있는 스냅샷이 새로운 커밋 객체로 저장됩니다.
logs/ – 레퍼런스 변경 히스토리
Git은 레퍼런스가 변경될 때마다 로그를 남깁니다.
logs/HEAD: HEAD가 이동한 모든 기록(체크아웃, 리베이스, 머지 등).logs/refs/heads/<branch>: 해당 브랜치가 업데이트된 내역.
이 로그는 git reflog 명령어가 내부적으로 읽어오는 파일이며, 실수로 삭제된 커밋을 복구할 때 유용합니다.
hooks/ – 자동화 스크립트
.git/hooks/ 디렉터리에는 다양한 이벤트에 연결할 수 있는 스크립트가 있습니다.
| 훅 이름 | 언제 실행되는가 |
|---|---|
pre-commit | git commit 직전에 실행 |
prepare-commit-msg | 커밋 메시지 템플릿이 만들어진 직후 |
commit-msg | 커밋 메시지가 입력된 후, 실제 커밋이 이루어지기 전 |
post-commit | 커밋이 성공적으로 완료된 뒤 |
pre-push | git push 직전에 원격에 전송될 커밋을 검사 |
pre-receive, update, post-receive | 원격 저장소에서 푸시를 받을 때 실행 (서버 측) |
스크립트는 실행 권한(chmod +x)을 부여해야 동작합니다.
요약
.git폴더는 Git이 모든 메타데이터와 객체를 보관하는 핵심 저장소입니다.- **
objects/**에 실제 데이터가 저장되고, **refs/**와 **HEAD**가 현재 상태를 가리킵니다. - **
index**는 스테이징 영역, **logs/**는 레퍼런스 히스토리, **hooks/**는 자동화 스크립트를 담당합니다. - 이 구조를 이해하면
git fsck,git reflog,git cat-file같은 저수준 명령을 활용해 복구·검사·디버깅을 할 수 있습니다.
Git 내부를 들여다보면, 단순히 “버전 관리”라는 개념을 넘어 객체 지향적인 데이터 저장소라는 점을 알 수 있습니다. 이제 .git 폴더가 어떻게 구성되어 있는지 알았으니, 필요할 때 직접 파일을 살펴보며 Git이 어떤 식으로 동작하는지 실험해 보세요!
소개
이 글에서는 Git을 구동하는 엔진인 .git 폴더를 자세히 살펴보겠습니다.
글을 다 읽고 나면 다음을 이해하게 됩니다:
- Git이 파일을 저장하고 히스토리를 내부적으로 추적하는 방법.
- 커밋이 내부적으로 어떻게 만들어지는지.
16진수 토끼굴에 들어가기 전에 다음에 익숙해져 있어야 합니다:
- 기본 Git 명령 –
git add,git commit,git push. - 명령줄 –
cd로 이동하고,ls로 목록을 보는 등. - 호기심 – 추상적인 개념을 탐구하려는 의지.
Git을 처음 사용하시나요?
If you need a refresher on the basics, check out:
- Git을 쉽게 배우기: 버전 관리 초보자 가이드
.git 폴더
컴퓨터에서 Git 저장소를 열고 “숨김 파일 표시”를 활성화하면 .git 라는 폴더가 보입니다.
- 이것은 단순한 설정 폴더가 아니라 데이터베이스입니다.
- 저장소의 두뇌, 심장, 영혼과 같습니다.
- 프로젝트 파일을 삭제하고
.git폴더만 남겨두면 모든 것을 복원할 수 있습니다. .git폴더를 삭제하면 저장소는 일반 텍스트 파일 폴더가 되며 모든 히스토리가 사라집니다.
Git은 본질적으로 콘텐츠 주소 지정 파일 시스템이며, 이는 키‑값 저장소라는 말의 멋진 표현입니다.
핵심 Git 객체
| 객체 | 저장 내용 | 사용 방식 |
|---|---|---|
| Blob | 원시 파일 내용 (예: main.ts). Git은 내용을 압축하여 블롭으로 저장합니다. | 데이터는 보관하지만 파일 이름은 없습니다. |
| Tree | 디렉터리 구조. 파일 이름(예: main.ts)을 블롭 ID에 매핑하고 다른 트리(하위 디렉터리)를 포함할 수 있습니다. | 폴더 계층 구조를 재구성합니다. |
| Commit | 특정 시점의 저장소 스냅샷. 트리에 대한 포인터, 메타데이터(작성자, 날짜, 메시지) 및 부모 커밋에 대한 포인터를 포함합니다. | 모든 것을 연결하고 히스토리 체인을 형성합니다. |
간단히 말하면
- Blob – 파일 데이터.
- Tree – 폴더 구조.
- Commit – 스냅샷(누가, 언제, 왜).
SHA‑1 (및 SHA‑256) 해시
아마 a1b2c3d…와 같은 긴 문자열을 본 적이 있을 것입니다. 이것은 SHA‑1 해시이며, 객체 내용에 수학 공식을 적용해 만든 40자 길이의 ID입니다.
- SHA = Secure Hash Algorithm(보안 해시 알고리즘).
- 최신 Git 버전은 SHA‑256도 지원하지만, GitHub, GitLab, 각종 도구 등 생태계가 아직 SHA‑1에 의존하고 있기 때문에 기본값은 SHA‑1입니다.
저장소에서 사용되는 해시 알고리즘 확인하기
git rev-parse --show-object-format
# Output: sha1 (or sha256)
rev-parse– Git 레퍼런스를 해석하고 파싱하는 저수준(plumbing) 명령.--show-object-format– 저장소에서 사용 중인 객체 해시 형식을 표시합니다.
편집기에서 저장소까지
단계 1 – git add .
무슨 일이 일어나나요:
- Git은 수정된 각 파일의 내용을 읽습니다.
- 내용에 대해 blob 객체를 생성하고 이를
.git/objects에 저장합니다. - 인덱스(스테이징 영역)를 업데이트합니다 – “다음 커밋을 위해, 이 파일 이름이 이 blob 해시를 가리킨다”는 목록입니다.
단계 2 – git commit -m "Message"
무슨 일이 일어나나요:
- 트리 생성 – Git은 인덱스를 순회하며 현재 폴더 구조를 나타내는 트리 객체를 만듭니다.
- 커밋 생성 – 최상위 트리와 이전 커밋(부모)을 가리키는 커밋 객체가 생성됩니다.
- HEAD 업데이트 –
HEAD포인터(현재 브랜치 라벨)가 새로운 커밋 ID로 이동합니다.
무결성 매직
- 파일의 해시(예:
"Hello World")는 항상 동일합니다. - 내용을 변경하면(예:
"Hello Worlds"), 완전히 다른 해시가 생성됩니다. - Git은 해시를 내용뿐만 아니라 객체 유형 및 크기까지 포함시켜 고유성과 무결성을 보장합니다.
각 커밋이 부모의 해시를 저장하기 때문에 전체 히스토리는 암호학적 체인을 형성합니다 – 어떤 객체라도 조작하면 체인이 끊어집니다.
HEAD 파일
HEAD는 현재 작업 중인 위치를 Git에 알려주는 작은 텍스트 파일입니다. 예시 내용:
ref: refs/heads/main
- 이는
main브랜치에 있다는 뜻입니다. git checkout dark-mode를 실행하면HEAD가ref: refs/heads/dark-mode로 업데이트됩니다.
.git 디렉터리 내부
| 디렉터리 / 파일 | 목적 |
|---|---|
| objects/ | SHA‑1 해시로 이름이 지정된 모든 Git 객체(블롭, 트리, 커밋, 태그)를 저장합니다. |
| refs/ | 북마크(브랜치와 태그)의 카탈로그입니다. |
| refs/heads/ | 각 브랜치에 대한 파일(e.g., feature-login). 각 파일에는 40자 커밋 해시가 들어 있습니다. |
| HEAD | 현재 브랜치를 가리킵니다(또는 분리된 HEAD 상태에서 직접 커밋을 가리킵니다). |
| index | 바이너리 스테이징 영역입니다. git add에 의해 업데이트되며, 타임스탬프, 파일명, 다음 커밋을 위한 블롭 해시를 보관합니다. |
객체 검사
객체는 압축된 바이너리 형태로 저장되므로 git cat-file로 열어볼 수 있습니다:
git cat-file -p <object-id>
# -p = pretty‑print (human‑readable)
커밋 객체의 예시 출력
tree 8d3a1...
parent 1f4e2...
author Satpal Rana 1703865000 +0000
Created the homepage hero section
요약
.git폴더는 blobs, trees, commits, references 를 포함하는 완전한 기능을 갖춘 데이터베이스입니다.- Git의 콘텐츠 주소 지정 저장소는 무결성을 보장하기 위해 SHA‑1(또는 선택적으로 SHA‑256) 해시를 사용합니다.
- 파일을 추가하면 blobs가 생성되고 index가 업데이트됩니다; 커밋을 하면 trees와 커밋 객체가 만들어지고 HEAD가 이동합니다.
- 브랜치는 커밋 해시를 가리키는 가벼운 포인터이며, 이를 통해 브랜치를 빠르게 생성하고 전환할 수 있습니다.
이제 Git 명령을 실행할 때마다 under the hood에서 무슨 일이 일어나는지 명확히 알 수 있습니다. 즐거운 탐구 되세요!
핸즈‑온 Git
저장소 구성
이 텍스트 파일에는 이 저장소에 특화된 구성 정보가 포함되어 있습니다. 예를 들면:
- 원격 저장소(
origin)의 URL. - 로컬 사용자 재정의.
- 브랜치 추적 정보.
새 저장소 만들기
git init demo
cd demo
파일을 만들고 커밋하기
echo "Hello Git" > hello.txt
git add .
git commit -m "First commit"
객체 탐색하기
# 저장소에 저장된 객체 목록 보기
ls .git/objects
# 특정 객체의 내용 보기 (실제 SHA‑1을 <sha>에 대입)
git cat-file -p <sha>
Git이 내부적으로 데이터를 어떻게 저장하고 검색하는지 관찰해 보세요.
결론
이 기사에서는 Git이 내부적으로 blobs, trees, commits, 그리고 hashes를 사용하여 데이터를 저장하는 방식을 탐구했습니다. 이를 이해하면 Git이 덜 신비롭고 더 예측 가능하게 느껴집니다.
“숨겨진 폴더는 때때로 가장 큰 비밀을 담고 있다.”
— Anonymous Developer