# 구조
# Git 내부 구조 (Basic)
---
## 1. Git은 파일 버전이 아닌 ****스냅샷 시스템****
Git은 "변경점(diff)"이 아니라, ****전체 프로젝트의 스냅샷(상태)을 저장****한다.
> 커밋 하나 = 전체 폴더의 압축 스냅샷 (단, 중복은 자동 제거됨)
---
## 2. Git의 3대 영역
```text
작업 디렉토리 → 스테이징 영역 → 로컬 저장소
(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란?
```bash
HEAD → 현재 체크아웃한 브랜치 or 커밋
```
- 보통은 `HEAD → main`
- `git checkout` 하면 HEAD가 다른 커밋을 가리킴
- `git reset`은 ****HEAD의 위치를 옮기는 것****
---
## 5. 브랜치란?
브랜치는 단지 ****커밋을 가리키는 포인터****이다.
```
A---B---C ← main (브랜치)
↑
HEAD
```
- 브랜치를 옮긴다 → 포인터 이동
- 커밋한다 → 현재 브랜치가 가리키는 곳에서 새로운 커밋 추가
---
## 6. Reflog란?
```bash
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 예시
```bash
e83c5163... ← 커밋, 블롭, 트리 모두 이 해시값으로 관리됨
```
### 1.3 내부 생성 방식
1. Git은 객체의 ****타입 + 크기 + 내용****을 문자열로 만듦
예: `blob 12\0Hello World\n`
2. 이를 SHA-1으로 해싱하여 파일 이름으로 저장
```bash
echo "Hello World" | git hash-object --stdin
→ 557db03de997c86a4a028e1ebd3a1ceb225be238
```
---
## 2. Git의 packfile 압축 구조
### 2.1 개요
Git은 수천 개의 객체를 `.git/objects` 디렉토리에 저장하지만, 리포지토리가 커지면 성능 저하가 발생합니다. 이를 해결하기 위해 \*\*packfile(.pack)\*\*을 사용합니다.
### 2.2 packfile이란?
> 여러 Git 객체를 ****압축하고 델타(차이)**** 형태로 저장한 파일
### 2.3 저장 구조
```text
.git/
└── objects/
├── pack/
│ ├── pack-xxxxx.pack ← 실제 압축된 객체
│ └── pack-xxxxx.idx ← 인덱스 파일
```
### 2.4 생성 명령어
```bash
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)
```bash
echo "Hello Git" > hello.txt
```
- 파일 생성됨
- 아직 Git은 이 파일을 추적하지 않음
---
## 2. `git add hello.txt`
```bash
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`
객체
| 커밋 메시지, 트리 포인터, 작성자 등 메타데이터 포함
|
```text
.git/objects/
├── 3a/...(blob)
├── 47/... (tree)
└── a1/... (commit)
```
#### .git/refs/heads/main
- 브랜치 포인터가 새 커밋 해시로 갱신됨
```text
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회 시)
```text
📁 Working Directory ← hello.txt 생성
↓ git add
📂 .git/index ← 스테이징 정보 저장
↓ git commit
📦 .git/objects/
├── blob (파일 내용)
├── tree (디렉토리 구조)
└── commit (메타데이터)
📄 .git/refs/heads/main ← 브랜치 → 커밋 연결
↑
📌 .git/HEAD ← 현재 브랜치 추적
🕓 .git/logs/ ← HEAD/브랜치 이력 추적
```
---
## 실제 파일 (커밋 후)
```bash
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 예시 명령어
```bash
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 예시 명령어
```bash
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 예시 명령어
```bash
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 예시 명령어
```bash
git stash
```
### 4.2 `.git` 내부 변화
구성 요소
| 변화 내용
|
---|
`.git/objects/`
| 현재 작업 상태(스냅샷)가 `stash`용 커밋으로 저장됨 (2~3개의 커밋 객체)
|
`.git/logs/refs/stash`
| 새로운 stash가 추가된 로그 생성
|
`.git/refs/stash`
| 가장 최신 stash를 가리키는 포인터 (없으면 새로 생성됨)
|
```bash
.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 예시 명령어
```bash
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 예시 명령어
```bash
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이 바라보는 위치
- 대부분 `ref: refs/heads/main` 형태
- ****HEAD → 브랜치 → 커밋****
### 🔹 `.git/objects/`
- Git의 핵심: 모든 파일/폴더/커밋을 ****SHA-1 해시값****으로 저장
- 하위 폴더 + 해시 기반 객체들
```bash
.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/`
- 커밋/푸시/머지 전후에 실행되는 자동화 스크립트
```text
pre-commit, post-commit, pre-push 등
```
---
## 3. 핵심 흐름
```text
📁 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
| 작업 보관소 (임시 커밋)
|
---