구조
- Git 내부 구조 (Basic)
- Git 내부 구조 (Advanced)
- commit 생성시 .git 내부 변화
- Git 명령어에 따른 .git 내부 구조 변화(1부)
- Git 명령어에 따른 .git 내부 구조 변화 (2부)
- 도식화
- 마인드맵
Git 내부 구조 (Basic)
1. Git은 파일 버전이 아닌 스냅샷 시스템
Git은 "변경점(diff)"이 아니라, 전체 프로젝트의 스냅샷(상태)을 저장한다.
커밋 하나 = 전체 폴더의 압축 스냅샷 (단, 중복은 자동 제거됨)
2. Git의 3대 영역
작업 디렉토리 → 스테이징 영역 → 로컬 저장소
(Working Directory) (Staging/Index) (Repository/.git)
코드 작성 git add git commit
영역 | 설명 |
---|---|
작업 디렉토리 | 실제로 코드 작성/수정하는 공간 |
스테이징 영역 (Index) | 커밋할 파일을 담아두는 임시 공간 ( |
로컬 저장소 | 커밋이 저장되는 |
3. 주요 Git 내부 객체
Git은 4가지 핵심 객체로 이루어져 있습니다:
객체 | 설명 | 예시 |
---|---|---|
🔹 Blob | 파일 내용 저장 (binary large object) |
|
🔸 Tree | 디렉토리 구조와 파일 리스트 | 폴더 구조 |
🔹 Commit | 커밋 메타데이터 + 부모 커밋 + tree | "커밋 메시지" |
🔸 Tag | 특정 커밋에 이름 부여 | v1.0.0 |
📦 커밋은 tree를 가리키고, tree는 blob들을 가리킵니다.
[commit]
|
v
[tree]
├── [blob] hello.txt
└── [blob] app.js
4. HEAD란?
HEAD → 현재 체크아웃한 브랜치 or 커밋
- 보통은
HEAD → main
git checkout
하면 HEAD가 다른 커밋을 가리킴git reset
은 HEAD의 위치를 옮기는 것
5. 브랜치란?
브랜치는 단지 커밋을 가리키는 포인터이다.
A---B---C ← main (브랜치)
↑
HEAD
- 브랜치를 옮긴다 → 포인터 이동
- 커밋한다 → 현재 브랜치가 가리키는 곳에서 새로운 커밋 추가
6. Reflog란?
git reflog
→ HEAD와 브랜치가 가리키던 이전 위치들의 로그
reset
이나checkout
후에도 추적 가능- 내부적으로 Git은 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 내부 생성 방식
- Git은 객체의 타입 + 크기 + 내용을 문자열로 만듦
예:blob 12\0Hello World\n
- 이를 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 내부 변화
시나리오
hello.txt
파일 생성git add hello.txt
git commit -m "Add hello"
1. 작업 디렉토리 (Working Directory)
echo "Hello Git" > hello.txt
- 파일 생성됨
- 아직 Git은 이 파일을 추적하지 않음
2. git add hello.txt
git add hello.txt
내부 변화:
구성요소 | 변화 내용 |
---|---|
| 스테이징 영역에 파일 등록됨 (경로, 해시, 권한 등 저장) |
|
의 내용이
객체로 저장됨 (SHA-1 해시 기반) |
📦 예시 구조:
.git/
└── objects/
└── 3a/
└── 3efbed4aef... ← hello.txt의 blob 객체
3. git commit -m "Add hello"
내부 변화:
.git/objects/
객체 | 내용 |
---|---|
객체 | 커밋 당시의 디렉토리 구조 (hello.txt 포함) |
객체 | 커밋 메시지, 트리 포인터, 작성자 등 메타데이터 포함 |
.git/objects/
├── 3a/...(blob)
├── 47/... (tree)
└── a1/... (commit)
.git/refs/heads/main
- 브랜치 포인터가 새 커밋 해시로 갱신됨
refs/heads/main → a1b2c3d4e5...
.git/HEAD
- 여전히
ref: refs/heads/main
상태 → main 브랜치를 따라감
.git/logs/HEAD & logs/refs/heads/main
- 커밋 전후
HEAD
포인터 변경 이력 추가됨 (reflog)
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
요약
단계 | 설명 |
---|---|
| blob 객체 생성 + index 등록 |
| tree + commit 객체 생성, 브랜치 포인터 이동 |
| objects, refs, HEAD, logs 전부 갱신 |
Git 명령어에 따른 .git 내부 구조 변화(1부)
1. git merge
시 내부 변화
1.1 예시 명령어
git checkout main
git merge feature
1.2 .git
내부 변화
구성 요소 | 변화 내용 |
---|---|
| 병합 결과로 새로운 merge commit 객체 생성 |
| 브랜치 포인터가 merge 커밋으로 이동 |
| 여전히 |
| 병합 대상 커밋( |
| 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
내부 변화
구성 요소 | 변화 내용 |
---|---|
|
|
| 브랜치가 새 커밋들로 덮어씀 |
| 리베이스 기준 커밋을 기록 |
| 여전히 |
| 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
내부 변화
구성 요소 | 변화 내용 |
---|---|
| 브랜치 포인터가 이전 커밋으로 이동 |
| 여전히 |
| 되돌린 커밋 시점으로 스테이징 영역 초기화 |
작업 디렉토리 |
|
| 이전 HEAD 커밋 해시를 저장 |
| 이동 전후 이력 기록됨 |
3.3 도식 예시
A---B---C ← main, HEAD
↑
ORIG_HEAD
▶ git reset --hard B
결과:
A---B ← main, HEAD
4. 특수 HEAD 파일 요약
파일 이름 | 생성 시점 | 설명 |
---|---|---|
|
| 병합 대상 커밋 해시 저장 |
|
| 기준 커밋 해시 저장 |
|
| 리셋 전 커밋 백업 |
|
| 원격에서 받아온 커밋들 정보 |
|
| 적용 대상 커밋 기록 |
5. 요약 비교표
명령어 | 커밋 이동 | 브랜치 이동 | HEAD 변경 | 디렉토리 영향 | 특수 파일 생성 |
---|---|---|---|---|---|
| ⭕ | ⭕ | ⭕ | 충돌 시 변동 있음 |
|
| ⭕ (rewrite) | ⭕ | ⭕ | 충돌 시 변동 있음 |
|
| ⭕ (이전 커밋으로) | ⭕ | ⭕ | ✔️ 완전 초기화 |
|
Git 명령어에 따른 .git 내부 구조 변화 (2부)
4. git stash
시 내부 변화
4.1 예시 명령어
git stash
4.2 .git
내부 변화
구성 요소 | 변화 내용 |
---|---|
| 현재 작업 상태(스냅샷)가 |
| 새로운 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
내부 변화
구성 요소 | 변화 내용 |
---|---|
| cherry-pick된 커밋 내용 기반으로 새 커밋 객체 생성 |
| 대상 커밋의 해시 저장 (충돌 발생 시 사용됨) |
| 현재 브랜치에 새 커밋 추가 |
| 병합 결과 반영 |
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
내부 변화
구성 요소 | 변화 내용 |
---|---|
| revert용 새 커밋 객체 생성 |
| C의 반대 연산 내용 반영 |
| 새 커밋으로 이동 |
revert
는 원본 커밋을 삭제하지 않고, "반대로 되돌리는" 커밋을 추가한다.
6.3 도식 예시
A---B---C ← HEAD
▶ git revert C
결과:
A---B---C---C' ← HEAD (C를 무효화하는 커밋)
7. 특수 파일 요약 (2부)
파일 이름 | 생성 명령어 | 설명 |
---|---|---|
|
| 적용 중인 커밋 해시 저장 (충돌 시 사용) |
|
| revert 진행 중인 커밋 정보 |
|
| 가장 최근 stash 참조 |
|
| stash 추가 이력 저장 |
8. 요약 비교표 (2부)
명령어 | 새 커밋 생성 | 기존 커밋 삭제 | HEAD 이동 | 특수 파일 | 비고 |
---|---|---|---|---|---|
| O (임시 커밋) | ❌ | ❌ |
| 작업 보관 |
| O | ❌ | O |
| 선택 커밋 복사 |
| O | ❌ | O |
| 기존 커밋 반전 |
도식화
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이 바라보는 위치
- 대부분
ref: refs/heads/main
형태 - HEAD → 브랜치 → 커밋
🔹 .git/objects/
- Git의 핵심: 모든 파일/폴더/커밋을 SHA-1 해시값으로 저장
- 하위 폴더 + 해시 기반 객체들
.git/objects/
├── a7/...
├── d1/...
└── pack/ ← packfile 압축 저장소
🔹 .git/refs/
- 브랜치/태그가 어떤 커밋을 가리키는지 저장
.git/refs/heads/main → a1b2c3d4e5 (커밋 해시)
🔹 .git/logs/
git reflog
명령에서 쓰이는 내부 이력HEAD
,branches
,remotes
이동 내역 저장
🔹 .git/index
- 스테이징 영역(index)의 내부 상태를 저장하는 바이너리 파일
git add
→ index에 등록 →git commit
때 커밋됨
🔹 .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 → 현재 브랜치 참조
요약
구성요소 | 설명 |
---|---|
| 현재 브랜치 또는 커밋을 가리킴 |
| 브랜치/태그 → 커밋 연결 |
| 모든 데이터(SHA-1 기반) 저장소 |
| 스테이징 상태 추적 |
| HEAD 및 브랜치 이동 이력 (reflog) |
| 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 | 작업 보관소 (임시 커밋) |