# 구조 # 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 작업 보관소 (임시 커밋)
---