Repository: 파일 변경 이력을 저장하는 Git의 프로젝트 저장소
Git의 저장소(Repository)는 프로젝트 파일과 그 변경 이력 전체를 담는 데이터베이스다. 작업 디렉터리(working directory)와 `.git` 디렉터리로 구성되며, 커밋(commit) 단위로 스냅샷(snapshot)을 쌓아 이력을 관리한다. 로컬 저장소와 원격 저장소(remote repository)의 관계를 이해하면 협업 흐름을 명확하게
By 송민성
1. 개념
저장소(Repository, 줄여서 repo)는 프로젝트의 파일과 그 파일들의 변경 이력을 함께 보관하는 공간이다. Git에서 저장소는 프로젝트 최상위 폴더 안의 .git 디렉터리에 저장된 데이터 전체를 가리킨다.
저장소는 위치에 따라 두 종류로 나뉜다.
- 로컬 저장소(local repository): 내 컴퓨터에 있는 저장소. 네트워크 없이도 커밋, 브랜치, 이력 조회가 가능하다.
- 원격 저장소(remote repository): GitHub, GitLab 같은 서버에 있는 저장소. 팀원과 코드를 공유하는 기준점 역할을 한다.
Git은 분산 버전 관리 시스템(DVCS, Distributed Version Control System)이므로, 모든 클론(clone)이 전체 이력을 가진 완전한 저장소다.
2. 왜 사용하는가
- 이력 추적: 누가, 언제, 무엇을, 왜 바꿨는지 커밋 단위로 남는다.
- 복구: 과거 시점의 상태로 되돌리거나 특정 변경만 취소할 수 있다.
- 병렬 작업: 브랜치(branch)로 여러 작업을 분리해 진행하고 나중에 병합(merge)한다.
- 협업: 원격 저장소를 기준으로 여러 개발자가 변경 사항을 주고받는다.
- 오프라인 작업: 로컬에 전체 이력이 있으므로 커밋과 로그 조회에 서버가 필요 없다.
3. 동작 원리
구성 요소
작업할 때 파일은 세 영역을 거친다.
- 작업 디렉터리(working directory): 실제로 파일을 편집하는 공간
- 스테이징 영역(staging area, index): 다음 커밋에 포함할 변경을 골라 두는 공간
- 저장소(`.git` 디렉터리): 커밋된 이력이 저장되는 공간
git add는 작업 디렉터리의 변경을 스테이징 영역으로 옮기고, git commit은 스테이징 영역의 내용을 저장소에 기록한다.
객체 데이터베이스
.git/objects에는 Git의 네 가지 객체가 저장된다.
| 객체 | 역할 |
|---|---|
| blob | 파일 내용 |
| tree | 디렉터리 구조 (blob과 하위 tree를 가리킴) |
| commit | tree 하나, 부모 커밋, 작성자, 메시지를 담은 스냅샷 |
| tag | 특정 객체에 붙인 이름표(주석 태그) |
각 객체는 내용으로부터 계산한 해시(hash) 값을 이름으로 쓰는 내용 주소 지정(content-addressable) 방식으로 저장된다. 같은 내용의 파일은 같은 blob을 공유하므로 중복 저장되지 않는다.
참조(ref)
브랜치와 태그는 커밋을 가리키는 참조(reference)이며 .git/refs에 저장된다. HEAD는 현재 체크아웃한 브랜치(또는 커밋)를 가리킨다.
원격 저장소와의 관계
git clone: 원격 저장소의 전체 이력을 복제하고origin이라는 이름으로 원격을 등록한다.git fetch: 원격의 새 커밋을 가져오되 내 브랜치는 건드리지 않는다.git pull: fetch 후 현재 브랜치에 통합한다(기본은 merge).git push: 내 커밋을 원격에 올린다.
4. 코드 예제
새 저장소를 만들고 커밋한 뒤 내부 구조를 확인하는 예제다.
# 실습용 임시 디렉터리에서 저장소 생성
mkdir demo-repo && cd demo-repo
git init
# 사용자 정보 설정 (이 저장소에만 적용)
git config user.name "Demo User"
git config user.email "demo@example.com"
# 파일 작성 후 상태 확인
echo "# Demo" > README.md
git status
# 스테이징 후 커밋
git add README.md
git commit -m "docs: add README"
# 이력 확인
git log --oneline
# 저장소 내부 확인
ls .git
git cat-file -t HEAD # commit
git cat-file -p HEAD # 커밋 내용 (tree, author, message)
git cat-file -p HEAD^{tree} # tree 내용 (README.md의 blob)원격 저장소와 연결하는 흐름은 다음과 같다.
# 기존 원격 저장소 복제
git clone https://github.com/example/project.git
cd project
# 원격 목록 확인
git remote -v
# 새 브랜치에서 작업 후 푸시
git switch -c feature/login
echo "login" > login.txt
git add login.txt
git commit -m "feat: add login file"
git push -u origin feature/login(두 번째 예제의 URL은 예시이므로 실제 주소로 바꿔 실행해야 한다.)
5. 시간 복잡도 또는 성능 특성
저장소 연산에 일반적인 시간복잡도 표기를 단정해 붙이기는 어렵고, 다음 특성만 정리한다.
- 로컬 연산이 빠르다: 커밋, 로그, diff, 브랜치 전환은 로컬 데이터만 읽으므로 네트워크 지연이 없다.
- 스냅샷 기반 저장: 커밋은 변경분이 아니라 프로젝트 전체 tree의 스냅샷을 가리킨다. 다만 변경되지 않은 파일은 같은 blob을 재사용한다.
- 팩 파일(packfile): Git은 객체를 압축하고 델타(delta) 방식으로 묶어 저장해 저장소 크기를 줄인다.
git gc로 정리할 수 있다. - 클론 비용: 기본 클론은 전체 이력을 받으므로 이력이 긴 저장소는 시간과 용량이 크다.
git clone --depth 1(얕은 클론, shallow clone)로 최신 커밋만 받을 수 있다.
6. 실무 사용 사례
- GitHub/GitLab 기반 협업: 원격 저장소를 중심으로 브랜치를 만들고 풀 리퀘스트(PR, Pull Request)로 리뷰한다.
- CI/CD 연동: 푸시나 PR 이벤트를 트리거로 테스트와 배포 파이프라인이 실행된다.
- 모노레포(monorepo)와 멀티레포(multi-repo): 여러 프로젝트를 한 저장소에 둘지, 프로젝트별로 나눌지 팀 구조에 맞춰 선택한다.
- 포크(fork) 워크플로: 오픈소스에서는 원본 저장소를 포크해 수정한 뒤 PR을 보낸다.
- 베어 저장소(bare repository): 작업 디렉터리 없이 이력만 가진 저장소로, 서버의 공유용 원격 저장소에 쓰인다(
git init --bare).
7. 주의할 점
- `.git` 디렉터리를 직접 수정하거나 삭제하지 않는다. 삭제하면 이력이 모두 사라지고 일반 폴더가 된다.
- 민감 정보 커밋 금지: 비밀번호, API 키가 한 번 커밋되면 이력에 남는다. 이후 파일을 지워도 과거 커밋에서 조회된다. 이미 푸시했다면 키를 폐기(rotate)하는 것이 우선이다.
- 대용량 바이너리: 큰 파일은 저장소 크기를 키운다. 필요하면 Git LFS를 검토한다.
- `.gitignore` 활용:
node_modules, 빌드 산출물,.env같은 파일은 추적 대상에서 제외한다. 이미 추적 중인 파일은.gitignore만으로 제외되지 않으며git rm --cached가 필요하다. - 공유한 이력 강제 변경 주의:
git push --force는 원격 이력을 덮어쓰므로 협업 중인 브랜치에서는 피한다. 불가피하면--force-with-lease를 쓴다. - 중첩 저장소: 저장소 안에 또 다른 저장소를 두면 혼란이 생긴다. 필요하면 서브모듈(submodule)을 사용한다.
8. 핵심 정리
- 저장소(Repository)는 프로젝트 파일과 전체 변경 이력을 담으며, 실체는
.git디렉터리다. - 파일은 작업 디렉터리 → 스테이징 영역 → 저장소 순서로 기록된다.
- Git은 blob, tree, commit, tag 객체를 해시 기반으로 저장하며, 브랜치와 태그는 커밋을 가리키는 참조다.
- 모든 클론이 전체 이력을 가진 완전한 저장소이므로 로컬 작업은 오프라인에서도 가능하다.
- 원격 저장소와는
clone,fetch,pull,push로 동기화한다. - 민감 정보 커밋과 공유 이력의 강제 푸시는 피해야 한다.