구조


Git 내부 구조 (Basic)


1. Git은 파일 버전이 아닌 스냅샷 시스템

Git은 "변경점(diff)"이 아니라, 전체 프로젝트의 스냅샷(상태)을 저장한다.

커밋 하나 = 전체 폴더의 압축 스냅샷 (단, 중복은 자동 제거됨)


2. Git의 3대 영역

작업 디렉토리      →    스테이징 영역       →    로컬 저장소
(Working Directory)     (Staging/Index)         (Repository/.git)
   코드 작성                 git add                 git commit

영역

설명

작업 디렉토리

실제로 코드 작성/수정하는 공간

스테이징 영역 (Index)

커밋할 파일을 담아두는 임시 공간 (git add)

로컬 저장소

커밋이 저장되는 .git 디렉토리


3. 주요 Git 내부 객체

Git은 4가지 핵심 객체로 이루어져 있습니다:

객체

설명

예시

🔹 Blob

파일 내용 저장 (binary large object)

hello.java 내용

🔸 Tree

디렉토리 구조와 파일 리스트

폴더 구조

🔹 Commit

커밋 메타데이터 + 부모 커밋 + tree

"커밋 메시지"

🔸 Tag

특정 커밋에 이름 부여

v1.0.0

📦 커밋은 tree를 가리키고, tree는 blob들을 가리킵니다.

[commit]
   |
   v
[tree]
 ├── [blob] hello.txt
 └── [blob] app.js

4. HEAD란?

HEAD → 현재 체크아웃한 브랜치 or 커밋

5. 브랜치란?

브랜치는 단지 커밋을 가리키는 포인터이다.

A---B---C  ← main (브랜치)
        ↑
      HEAD

6. Reflog란?

git reflog

→ HEAD와 브랜치가 가리키던 이전 위치들의 로그


7. .git 디렉토리 구조 요약

.git/
├── objects/       ← 커밋, 트리, 블롭, 태그 객체 저장소
├── refs/          ← 브랜치, 태그 등의 포인터
├── HEAD           ← 현재 가리키는 브랜치
├── index          ← 스테이징 정보
├── logs/          ← reflog 정보 저장
└── config         ← Git 설정

📌 정리

개념

설명

Commit

전체 스냅샷 + 부모 커밋 정보

Blob

파일 내용 저장

Tree

폴더 구조

Branch

커밋을 가리키는 포인터

HEAD

현재 브랜치 or 커밋

Staging Area

다음 커밋을 준비하는 공간

Reflog

HEAD의 이동 이력 추적 가능 (복구에 유용)



Git 내부 구조 (Advanced)


1. 🔐 Git 객체의 SHA-1 해시 구조

1.1 개요

Git은 모든 객체(blob, tree, commit 등)를 SHA-1 해시 값을 통해 식별한다.

하나의 커밋은 고유한 40자리 16진수 해시로 구분됨

1.2 예시

e83c5163... ← 커밋, 블롭, 트리 모두 이 해시값으로 관리됨

1.3 내부 생성 방식

  1. Git은 객체의 타입 + 크기 + 내용을 문자열로 만듦
    예: blob 12\0Hello World\n
  2. 이를 SHA-1으로 해싱하여 파일 이름으로 저장
echo "Hello World" | git hash-object --stdin
→ 557db03de997c86a4a028e1ebd3a1ceb225be238

2. Git의 packfile 압축 구조

2.1 개요

Git은 수천 개의 객체를 .git/objects 디렉토리에 저장하지만, 리포지토리가 커지면 성능 저하가 발생합니다. 이를 해결하기 위해 **packfile(.pack)**을 사용합니다.

2.2 packfile이란?

여러 Git 객체를 압축하고 델타(차이) 형태로 저장한 파일

2.3 저장 구조

.git/
└── objects/
    ├── pack/
    │   ├── pack-xxxxx.pack   ← 실제 압축된 객체
    │   └── pack-xxxxx.idx    ← 인덱스 파일

2.4 생성 명령어

git gc      # 자동으로 packfile 생성 (garbage collection)

2.5 특징

특징

설명

공간 절약

비슷한 파일은 델타 방식으로 저장됨

빠른 복사

clone, fetch, push 성능 향상

불변성 보장

packfile 내 객체는 변경 불가, 안전함


3. Git vs SVN 비교

항목

Git

SVN

저장 방식

분산 버전 관리 (DVCS)

중앙 집중식 (CVCS)

커밋 저장소

로컬과 원격 모두

중앙 서버

브랜치

가볍고 빠름 (포인터)

디렉토리 복사 방식

네트워크 필요 여부

X (로컬 커밋 가능)

O (항상 서버 접속 필요)

속도

빠름 (로컬 기반)

느림 (서버 기반)

merge & rebase

고급 기능 다양

제한적 기능

사용 예

GitHub, GitLab, OSS 등

일부 기업 내부 시스템

3.1 핵심 차이

| Git은 로컬에서도 모든 기능 사용 가능, 브랜치가 lightweight
→ 오프라인, 분기 많은 프로젝트에 최적화

| SVN은 중앙 서버 기반으로 단순하고 통제된 작업에 적합
→ 사내 규칙이 명확한 환경에 적합


요약

주제

요점

SHA-1 해시

Git 객체는 타입+내용 기반으로 해시 생성

packfile

성능 최적화를 위한 객체 압축 저장소

Git vs SVN

Git은 분산 & 유연, SVN은 중앙 & 단순



commit 생성시 .git 내부 변화


시나리오

  1. hello.txt 파일 생성
  2. git add hello.txt
  3. git commit -m "Add hello"

1. 작업 디렉토리 (Working Directory)

echo "Hello Git" > hello.txt

2. git add hello.txt

git add hello.txt

내부 변화:

구성요소

변화 내용

.git/index

스테이징 영역에 파일 등록됨 (경로, 해시, 권한 등 저장)

.git/objects/

hello.txt

의 내용이

blob

객체로 저장됨 (SHA-1 해시 기반)

📦 예시 구조:

.git/
└── objects/
    └── 3a/
        └── 3efbed4aef... ← hello.txt의 blob 객체

3. git commit -m "Add hello"

내부 변화:

.git/objects/

객체

내용

tree

객체

커밋 당시의 디렉토리 구조 (hello.txt 포함)

commit

객체

커밋 메시지, 트리 포인터, 작성자 등 메타데이터 포함

.git/objects/
├── 3a/...(blob)
├── 47/... (tree)
└── a1/... (commit)

.git/refs/heads/main

refs/heads/main → a1b2c3d4e5...

.git/HEAD

.git/logs/HEAD & logs/refs/heads/main

0000000 → a1b2c3d4 Commit: Add hello

전체 흐름 (커밋 1회 시)

📁 Working Directory       ← hello.txt 생성
    ↓ git add
📂 .git/index              ← 스테이징 정보 저장
    ↓ git commit
📦 .git/objects/
    ├── blob (파일 내용)
    ├── tree (디렉토리 구조)
    └── commit (메타데이터)

📄 .git/refs/heads/main    ← 브랜치 → 커밋 연결
    ↑
📌 .git/HEAD               ← 현재 브랜치 추적
🕓 .git/logs/              ← HEAD/브랜치 이력 추적

실제 파일 (커밋 후)

cat .git/HEAD
# ref: refs/heads/main

cat .git/refs/heads/main
# a1b2c3d4e5...

git ls-tree HEAD
# 100644 blob 3a3efbed...	hello.txt

git cat-file -p <커밋해시>
# tree 47fa...
# author ...
# message: Add hello

요약

단계

설명

git add

blob 객체 생성 + index 등록

git commit

tree + commit 객체 생성, 브랜치 포인터 이동

.git 내부

objects, refs, HEAD, logs 전부 갱신




Git 명령어에 따른 .git 내부 구조 변화(1부)


1. git merge 시 내부 변화

1.1 예시 명령어


git checkout main
git merge feature

1.2 .git 내부 변화

구성 요소

변화 내용

.git/objects/

병합 결과로 새로운 merge commit 객체 생성

.git/refs/heads/main

브랜치 포인터가 merge 커밋으로 이동

.git/HEAD

여전히 ref: refs/heads/main 유지

.git/MERGE_HEAD

병합 대상 커밋(feature) 해시 저장 (병합 중일 때 생성됨)

.git/logs/HEAD

HEAD의 이동 이력 반영됨 (reflog)

1.3 도식 예시


A---B---C ← main
     \    
      D---E ← feature

▶ git merge feature

결과:

A---B---C-------M (merge commit) ← main, HEAD
     \         /
      D---E

2. git rebase 시 내부 변화

2.1 예시 명령어


git checkout feature
git rebase main

2.2 .git 내부 변화

구성 요소

변화 내용

.git/objects/

feature의 커밋들을 기반 변경 후 새 커밋으로 재작성

.git/refs/heads/feature

브랜치가 새 커밋들로 덮어씀

.git/REBASE_HEAD

리베이스 기준 커밋을 기록

.git/HEAD

여전히 ref: refs/heads/feature

.git/logs/HEAD

HEAD의 커밋 재작성 이력 반영됨

2.3 도식 예시


main:    A---B---C
feature:           D---E

▶ git rebase main

결과:
main:    A---B---C
feature:           D'---E' ← HEAD

원래 커밋 D, E는 삭제되지 않고 .git/objects에 보존됨


3. git reset 시 내부 변화

3.1 예시 명령어


git reset --hard HEAD~1

3.2 .git 내부 변화

구성 요소

변화 내용

.git/refs/heads/main

브랜치 포인터가 이전 커밋으로 이동

.git/HEAD

여전히 ref: refs/heads/main

.git/index

되돌린 커밋 시점으로 스테이징 영역 초기화

작업 디렉토리

--hard인 경우 파일도 초기화

.git/ORIG_HEAD

이전 HEAD 커밋 해시를 저장

.git/logs/HEAD

이동 전후 이력 기록됨

3.3 도식 예시


A---B---C ← main, HEAD
        ↑
     ORIG_HEAD

▶ git reset --hard B

결과:

A---B ← main, HEAD

4. 특수 HEAD 파일 요약

파일 이름

생성 시점

설명

.git/MERGE_HEAD

git merge 수행 중

병합 대상 커밋 해시 저장

.git/REBASE_HEAD

git rebase 수행 중

기준 커밋 해시 저장

.git/ORIG_HEAD

git reset, merge

리셋 전 커밋 백업

.git/FETCH_HEAD

git fetch 이후

원격에서 받아온 커밋들 정보

.git/CHERRY_PICK_HEAD

git cherry-pick 중 충돌 시

적용 대상 커밋 기록


5. 요약 비교표

명령어

커밋 이동

브랜치 이동

HEAD 변경

디렉토리 영향

특수 파일 생성

merge

충돌 시 변동 있음

MERGE_HEAD

rebase

⭕ (rewrite)

충돌 시 변동 있음

REBASE_HEAD

reset --hard

⭕ (이전 커밋으로)

✔️ 완전 초기화

ORIG_HEAD




Git 명령어에 따른 .git 내부 구조 변화 (2부)


4. git stash 시 내부 변화

4.1 예시 명령어

git stash

4.2 .git 내부 변화

구성 요소

변화 내용

.git/objects/

현재 작업 상태(스냅샷)가 stash용 커밋으로 저장됨 (2~3개의 커밋 객체)

.git/logs/refs/stash

새로운 stash가 추가된 로그 생성

.git/refs/stash

가장 최신 stash를 가리키는 포인터 (없으면 새로 생성됨)

.git/
├── objects/        ← stash 내용 포함 커밋 객체 추가
├── refs/stash      ← 최신 stash 참조
├── logs/refs/stash ← stash 이력 저장

4.3 도식 예시

main:    A---B---C
               ↑
           HEAD / index

▶ git stash

결과:
- 워킹 디렉토리와 인덱스 초기화됨
- .git/refs/stash → stash 커밋 가리킴

5. git cherry-pick 시 내부 변화

5.1 예시 명령어

git cherry-pick a1b2c3d

5.2 .git 내부 변화

구성 요소

변화 내용

.git/objects/

cherry-pick된 커밋 내용 기반으로 새 커밋 객체 생성

.git/CHERRY_PICK_HEAD

대상 커밋의 해시 저장 (충돌 발생 시 사용됨)

.git/HEAD

현재 브랜치에 새 커밋 추가

.git/index

병합 결과 반영

5.3 도식 예시

main:    A---B---C ← HEAD
feature:         D---E ← cherry-pick 대상

▶ git cherry-pick E

결과:
main:    A---B---C---E' ← HEAD

E와 동일한 내용이지만 새 커밋 E′가 만들어짐


6. git revert 시 내부 변화

6.1 예시 명령어

git revert C

6.2 .git 내부 변화

구성 요소

변화 내용

.git/objects/

revert용 새 커밋 객체 생성

.git/index

C의 반대 연산 내용 반영

.git/HEAD

새 커밋으로 이동

revert는 원본 커밋을 삭제하지 않고, "반대로 되돌리는" 커밋을 추가한다.

6.3 도식 예시

A---B---C ← HEAD

▶ git revert C

결과:

A---B---C---C' ← HEAD (C를 무효화하는 커밋)

7. 특수 파일 요약 (2부)

파일 이름

생성 명령어

설명

.git/CHERRY_PICK_HEAD

git cherry-pick

적용 중인 커밋 해시 저장 (충돌 시 사용)

.git/REVERT_HEAD

git revert (중단 시)

revert 진행 중인 커밋 정보

.git/refs/stash

git stash

가장 최근 stash 참조

.git/logs/refs/stash

git stash

stash 추가 이력 저장


8. 요약 비교표 (2부)

명령어

새 커밋 생성

기존 커밋 삭제

HEAD 이동

특수 파일

비고

stash

O (임시 커밋)

refs/stash

작업 보관

cherry-pick

O

O

CHERRY_PICK_HEAD

선택 커밋 복사

revert

O

O

REVERT_HEAD

기존 커밋 반전




도식화


1. 전체 구조 개요

.git/
├── HEAD                  ← 현재 가리키는 브랜치 (예: ref: refs/heads/main)
├── config                ← 로컬 Git 설정
├── description           ← 주로 bare repo에서 사용
├── index                 ← 스테이징 영역 정보 (트래킹 중인 파일 목록)
├── objects/              ← Git 객체 저장소 (blob, tree, commit, tag)
│   ├── xx/xxxx...        ← SHA-1 해시로 저장된 개별 객체
│   └── pack/             ← 압축된 객체 저장소 (.pack, .idx)
├── refs/                 ← 브랜치, 태그 등 참조(포인터)
│   ├── heads/            ← 브랜치 참조 (예: main, feature)
│   ├── remotes/          ← 원격 브랜치 정보 (예: origin/main)
│   └── tags/             ← 태그 정보
├── logs/                 ← HEAD 및 refs의 이동 이력 (reflog 저장소)
│   ├── HEAD
│   └── refs/
├── info/                 ← exclude 설정 등 부가 정보
└── hooks/                ← 커밋, 푸시 등 Git 이벤트용 스크립트

2. 각 구성 요소 설명

🔹 .git/HEAD

🔹 .git/objects/

.git/objects/
├── a7/...
├── d1/...
└── pack/    ← packfile 압축 저장소

🔹 .git/refs/

.git/refs/heads/main → a1b2c3d4e5 (커밋 해시)

🔹 .git/logs/

🔹 .git/index

🔹 .git/hooks/

pre-commit, post-commit, pre-push 등

3. 핵심 흐름

📁 Working Directory
   ↓ git add
📂 .git/index (Staging Area)
   ↓ git commit
📦 .git/objects/ (커밋, 트리, 블롭 저장)
   ↓ 브랜치 포인터 이동
📄 .git/refs/heads/main
   ↑ HEAD → 현재 브랜치 참조

요약

구성요소

설명

HEAD

현재 브랜치 또는 커밋을 가리킴

refs

브랜치/태그 → 커밋 연결

objects

모든 데이터(SHA-1 기반) 저장소

index

스테이징 상태 추적

logs

HEAD 및 브랜치 이동 이력 (reflog)

hooks

Git 이벤트 발생 시 실행되는 스크립트



마인드맵


Git 내부 구조
├── 1. Working Directory
│   └── 실제 작업 공간 (코드 작성, 수정)
│
├── 2. Index (Staging Area) ← .git/index
│   └── git add로 관리됨
│
├── 3. Local Repository (.git/)
│   ├── 3.1 objects/
│   │   ├── blob: 파일 내용
│   │   ├── tree: 디렉토리 구조
│   │   └── commit: 스냅샷 + 부모 참조 + 메타
│   │
│   ├── 3.2 refs/
│   │   ├── heads/: 브랜치 포인터
│   │   ├── remotes/: 원격 브랜치
│   │   └── tags/: 태그 포인터
│   │
│   ├── 3.3 HEAD
│   │   ├── 현재 브랜치 참조 (예: ref: refs/heads/main)
│   │   └── detached 상태 가능
│   │
│   ├── 3.4 logs/
│   │   └── HEAD 및 refs의 이동 이력 (reflog)
│   │
│   ├── 3.5 config
│   │   └── 사용자 설정 정보
│   │
│   ├── 3.6 hooks/
│   │   └── pre-commit, post-commit 등 자동화 스크립트
│   │
│   └── 3.7 특수 HEAD 파일
│       ├── MERGE_HEAD        ← merge 중 생성
│       ├── REBASE_HEAD       ← rebase 중 생성
│       ├── ORIG_HEAD         ← reset 전 위치 백업
│       ├── CHERRY_PICK_HEAD  ← cherry-pick 중 충돌 시
│       ├── REVERT_HEAD       ← revert 충돌 시
│       └── FETCH_HEAD        ← fetch 결과
│
├── 4. 명령어 동작 흐름
│   ├── git add
│   │   └── 파일 → index 등록
│   ├── git commit
│   │   ├── index → commit 객체 생성
│   │   └── 브랜치 포인터 → 새 커밋
│   ├── git reset
│   │   ├── HEAD/브랜치 포인터 이동
│   │   └── --hard 시 index + 작업 디렉토리도 초기화
│   ├── git merge
│   │   ├── merge commit 생성
│   │   └── MERGE_HEAD 기록
│   ├── git rebase
│   │   ├── 커밋 재작성 (rewrite)
│   │   └── REBASE_HEAD 기록
│   ├── git cherry-pick
│   │   ├── 커밋 복사
│   │   └── CHERRY_PICK_HEAD 기록
│   ├── git revert
│   │   ├── 반전 커밋 추가
│   │   └── REVERT_HEAD 기록
│   └── git stash
│       ├── 현재 상태를 임시 커밋으로 보관
│       ├── refs/stash 생성
│       └── logs/refs/stash 이력 저장
│
└── 5. 복구 및 확인
    ├── git reflog  → HEAD, 브랜치 이동 이력 추적
    ├── git log     → 커밋 히스토리
    ├── git cat-file -p <해시> → 객체 내용 확인
    └── git fsck     → 저장소 무결성 점검

요약

키워드

의미

blob

파일 내용

tree

폴더 구조

commit

전체 스냅샷

HEAD

현재 위치 추적 포인터

refs

브랜치/태그가 가리키는 대상

logs

HEAD/브랜치 이동 기록 (reflog)

index

커밋 준비 상태 저장

stash

작업 보관소 (임시 커밋)