Staging Area: 커밋할 변경 사항을 미리 골라 담는 Git의 중간 영역
스테이징 영역(Staging Area, Index)은 작업 디렉터리와 저장소 사이에서 다음 커밋에 포함할 변경 사항을 모아 두는 공간이다. `git add`로 파일이나 일부 변경 조각(hunk)만 골라 올리면, `git commit`은 그 상태만 스냅샷으로 기록한다. 이 구조 덕분에 한 번에 여러 작업을 했더라도 논리적 단위로 나누어 커밋할 수 있다.
By 송민성
1. 개념
스테이징 영역(Staging Area)은 다음 커밋에 들어갈 내용을 구성해 두는 공간이다. Git 내부에서는 인덱스(Index)라고 부르며, 실제로는 .git/index 파일에 저장된다.
Git은 파일이 세 가지 영역을 오간다고 볼 수 있다.
| 영역 | 설명 |
|---|---|
| 작업 디렉터리(Working Directory) | 실제로 편집하는 파일들 |
| 스테이징 영역(Staging Area) | 다음 커밋에 포함하기로 한 변경 사항 |
| 저장소(Repository, .git) | 커밋으로 확정된 이력 |
2. 왜 사용하는가
- 커밋 단위를 논리적으로 분리: 버그 수정과 리팩터링을 동시에 했더라도 각각 다른 커밋으로 남길 수 있다.
- 커밋 전 검토: 올라간 내용을
git diff --staged로 확인한 뒤 확정할 수 있다. - 파일 내부의 부분 선택: 한 파일 안의 일부 변경만 커밋할 수 있다(
git add -p). - 리뷰와 되돌리기 용이: 작은 커밋은 코드 리뷰,
git revert,git bisect에서 다루기 쉽다.
3. 동작 원리
git add를 실행하면 Git은 다음 일을 한다.
- 파일 내용을 압축해 블롭(blob) 객체로
.git/objects에 저장한다. - 인덱스에 "이 경로는 이 블롭을 가리킨다"는 항목(경로, 파일 모드, 객체 해시)을 기록한다.
git commit을 실행하면 인덱스의 내용으로 트리(tree) 객체를 만들고, 이 트리를 가리키는 커밋 객체를 생성한다. 커밋은 작업 디렉터리가 아니라 인덱스를 기준으로 만들어진다. 그래서 git add 이후에 파일을 다시 수정하면, 그 추가 수정은 스테이징되지 않은 상태로 남는다.
각 파일은 비교 기준에 따라 상태가 나뉜다.
- Untracked: Git이 아직 추적하지 않는 파일
- Modified: 마지막 커밋 대비 바뀌었지만 스테이징되지 않음
- Staged: 다음 커밋에 포함되도록 인덱스에 올라감
4. 코드 예제
실습용 저장소를 만들어 흐름을 확인하는 셸 스크립트이다.
#!/bin/sh
set -e
dir=$(mktemp -d)
cd "$dir"
git init -q
git config user.name "demo"
git config user.email "demo@example.com"
# 1) 초기 커밋
printf 'line1\n' > app.txt
git add app.txt
git commit -q -m "init"
# 2) 파일 수정 + 새 파일 추가
printf 'line1\nline2\n' > app.txt
printf 'notes\n' > notes.txt
git status --short
# M app.txt
# ?? notes.txt
# 3) app.txt만 스테이징
git add app.txt
git status --short
# M app.txt
# ?? notes.txt
# 4) 스테이징 후 추가 수정 -> 같은 파일이 두 상태를 동시에 가짐
printf 'line1\nline2\nline3\n' >> app.txt
git status --short
# MM app.txt
git diff # 작업 디렉터리 vs 인덱스 (line3만 보임)
git diff --staged # 인덱스 vs HEAD (line2만 보임)
# 5) 스테이징된 내용만 커밋
git commit -q -m "add line2"
git status --short
# M app.txt (line3은 아직 커밋되지 않음)
# ?? notes.txt
# 6) 스테이징 취소 예시
git add app.txt
git restore --staged app.txt # 인덱스에서만 내림, 파일 내용은 유지
git status --short파일 내부의 일부만 올리려면 대화형 모드를 쓴다.
git add -p app.txt
# y: 이 조각 스테이징, n: 건너뜀, s: 더 작게 분할, q: 종료5. 시간 복잡도 또는 성능 특성
Git은 인덱스에 파일별 메타데이터(수정 시각, 크기 등)를 캐시해 둔다. git status는 이를 이용해 내용을 매번 전부 읽지 않고도 변경 여부를 빠르게 판단할 수 있다. 다만 변경된 파일은 새로 해시를 계산해야 하므로, 대용량 파일을 자주 git add하면 비용이 커진다. 정확한 소요 시간은 저장소 크기와 파일 시스템에 따라 달라지므로 일반적인 수치로 단정할 수 없다.
6. 실무 사용 사례
- 기능 단위 커밋 분리: 한 번에 작업한 변경을
git add -p로 나눠 "버그 수정", "포맷팅", "테스트 추가"처럼 별도 커밋으로 만든다. - 커밋 전 자기 리뷰:
git diff --staged로 디버깅용console.log나 임시 코드가 섞이지 않았는지 확인한다. - 훅(hook) 연동:
pre-commit훅이나 lint-staged 같은 도구는 스테이징된 파일만 대상으로 린트와 포맷을 실행한다. - 직전 커밋 보완: 빠뜨린 파일을
git add한 뒤git commit --amend로 마지막 커밋에 합친다.
7. 주의할 점
git add후 다시 수정한 내용은 자동으로 반영되지 않는다. 커밋 전에git status로MM표시가 없는지 확인한다.git add .은 의도하지 않은 파일(.env, 빌드 산출물)까지 올릴 수 있다..gitignore를 정비하고git status로 확인한다.- 이미 추적 중인 파일은
.gitignore에 추가해도 무시되지 않는다.git rm --cached <파일>로 추적을 해제해야 한다. - 스테이징 취소에는
git restore --staged <파일>을 쓴다. 반면git restore <파일>(옵션 없음)은 작업 디렉터리의 수정 내용을 버리므로 복구할 수 없다. - 시크릿을 한 번
git add하면 객체 저장소에 블롭이 남을 수 있다. 커밋하지 않았더라도 노출 가능성을 염두에 둬야 한다.
8. 핵심 정리
- 스테이징 영역(인덱스)은 다음 커밋의 내용을 구성하는 중간 공간이다.
- 커밋은 작업 디렉터리가 아니라 인덱스의 내용으로 만들어진다.
git add로 올리고,git restore --staged로 내리며,git diff --staged로 확인한다.git add -p를 쓰면 한 파일 안에서도 변경 조각 단위로 골라 커밋할 수 있다.git add이후의 추가 수정은 다시git add해야 커밋에 포함된다.