Git 내부: 작동 원리와 .git 폴더의 역할
Source: Dev.to
Introduction
많은 개발자에게 Git은 마법 같은 주문처럼 느껴집니다. 우리는 git add . 를 입력하고 git commit -m "fixed stuff" 로 커밋한 뒤 원격 서버에 푸시하고, 최선의 결과를 기대합니다. 잘 동작하면 환상적이지만, 문제가 생기면 눈을 가린 채 폭탄을 해제하려는 기분이 듭니다.
표면 아래에서 무슨 일이 일어나는지를 이해하면, 암기식 사용에서 진정한 숙련도로 전환할 수 있습니다. Git은 단순히 명령어 모음이 아니라 정보를 관리하도록 정교하게 설계된 시스템입니다. 그 층을 하나씩 벗겨내면 Git이 실제로 “생각”하는 방식을 머릿속에 그릴 수 있습니다.
The .git Folder
리포지토리의 숨겨진 핵심은 .git 폴더입니다. 파일 탐색기에서는 보통 숨김 처리되어 있는데, 수동으로 변경하면 리포지토리가 손상될 수 있기 때문입니다.
- Working directory –
.git외부의 모든 것; 파일을 편집하는 샌드박스. .gitfolder – 모든 파일 버전, 전체 커밋 히스토리, 모든 브랜치를 저장하는 데이터베이스.
Important:
.git폴더를 삭제하면 전체 프로젝트 히스토리가 사라지고, 디스크에 남아 있는 현재 파일만 남게 됩니다.
Key Sub‑directories and Files
| Path | Description |
|---|---|
objects/ | 모든 파일 내용과 히스토리를 저장합니다(데이터베이스의 핵심). |
refs/ | 브랜치(heads/)와 태그와 같은 포인터(레퍼런스)를 보관합니다. |
HEAD | 현재 어떤 브랜치에 있는지를 나타내는 평문 파일입니다. |
Git은 키‑값 저장소처럼 동작합니다. 키는 내용으로부터 생성된 40자 SHA‑1 해시이며, 내용이 조금이라도 바뀌면 완전히 다른 해시가 생성되어 데이터 무결성을 보장합니다.
Git’s Data Model
Object Types
Git은 objects/ 안에 세 가지 주요 객체 유형을 저장합니다:
Blob
- 파일의 원시 내용을 포함합니다.
- 파일 이름이나 위치는 저장하지 않습니다.
- 서로 다른 파일에 동일한 내용이 있으면 하나의 Blob이 공유됩니다.
Tree
- 디렉터리를 나타냅니다.
- Blob(파일)과 다른 Tree(하위 디렉터리)를 가리키는 항목들을 파일명과 함께 포함합니다.
Commit
- 모든 것을 하나의 스냅샷으로 묶습니다.
- 포함 내용:
- 최상위 Tree(그 시점의 프로젝트 루트)를 가리키는 포인터.
- 메타데이터: 작성자, 타임스탬프, 커밋 메시지.
- 이전 Commit(이전 스냅샷)을 가리키는 포인터.
이 객체들을 이해하면 staging area(인덱스) 역할이 명확해집니다.
The Staging Area (Index)
인덱스는 다음 스냅샷에 포함될 Blob들을 기록합니다.
Adding a File (git add)
git add style.css
git add 를 실행하면:
- Git은 파일 내용을 Blob으로 압축합니다.
- Blob의 SHA‑1 해시를 계산하고
.git/objects/에 Blob을 저장합니다. - 인덱스가
style.css를 해당 Blob 해시와 매핑하도록 업데이트되어, 파일이 다음 커밋에 포함될 것임을 표시합니다.
Creating a Commit (git commit)
git commit -m "Added Styles"
git commit 을 실행하면:
- Git은 인덱스에 기록된 Blob 해시를 사용해 현재 디렉터리 구조를 반영하는 Tree 객체를 생성합니다.
- 이 Tree를 가리키고 이전 Commit을 가리키는 Commit 객체를 만듭니다.
- 현재 브랜치 레퍼런스(예:
refs/heads/main)를 새로운 Commit 해시로 이동시킵니다.
작업 디렉터리 → Blob → Tree → Commit 흐름을 시각화하면 Git이 히스토리를 어떻게 기록하는지, 그리고 git add와 git commit 같은 동작이 왜 그렇게 동작하는지를 정확히 이해할 수 있습니다.