CS학습5 min read
Working Tree: 커밋 전 파일을 직접 편집하는 작업 디렉터리
워킹 트리(Working Tree)는 Git 저장소에서 개발자가 실제로 파일을 열어 수정하는 작업 디렉터리다. 커밋된 스냅샷을 체크아웃한 결과물이며, 스테이징 영역(Index), 저장소(Repository)와 구분되는 세 번째 영역이다. 워킹 트리의 상태를 읽고 되돌리는 명령(`status`, `diff`, `restore`, `stash`, `clean`
By 송민성
1. 개념
워킹 트리(Working Tree)는 Git이 관리하는 프로젝트 디렉터리에서 .git 디렉터리를 제외한, 개발자가 눈으로 보고 편집기로 수정하는 실제 파일 집합이다. 작업 디렉터리(Working Directory)라고도 부른다.
Git은 파일의 상태를 저장하는 영역을 세 곳으로 나눈다.
| 영역 | 위치 | 역할 |
|---|---|---|
| 워킹 트리(Working Tree) | 프로젝트 폴더의 일반 파일 | 실제로 편집하는 파일 |
| 스테이징 영역(Index, Staging Area) | .git/index | 다음 커밋에 포함할 내용을 모아 둔 목록 |
| 저장소(Repository) | .git/objects | 커밋된 이력(스냅샷) |
워킹 트리의 각 파일은 크게 두 상태로 나뉜다.
- 추적됨(tracked): 마지막 커밋이나 인덱스에 존재하는 파일. 수정되지 않음(unmodified) 또는 수정됨(modified) 상태가 된다.
- 추적되지 않음(untracked): Git이 아직 알지 못하는 새 파일(무시 규칙에 걸린 파일 제외).
2. 왜 사용하는가
워킹 트리가 저장소와 분리되어 있기 때문에 다음이 가능하다.
- 커밋 이력을 건드리지 않고 자유롭게 실험하고 수정할 수 있다.
- 수정한 내용 중 일부만 골라 커밋할 수 있다(워킹 트리 → 인덱스 → 커밋의 단계 구조).
- 마음에 들지 않으면 마지막 커밋 상태로 되돌릴 수 있다.
git worktree로 하나의 저장소에서 여러 워킹 트리를 동시에 열어 브랜치별로 병행 작업할 수 있다.
3. 동작 원리
데이터의 흐름은 다음과 같다.
text
워킹 트리 --git add--> 인덱스 --git commit--> 저장소
워킹 트리 <--git restore-- 인덱스
워킹 트리 <--git switch/checkout-- 저장소git switch로 브랜치를 바꾸거나git checkout을 하면, Git은 대상 커밋의 스냅샷을 워킹 트리에 풀어 놓는다.git status는 두 가지 비교를 수행한다. 첫째 HEAD와 인덱스의 차이(커밋할 변경 사항), 둘째 인덱스와 워킹 트리의 차이(아직 스테이징하지 않은 변경 사항). 여기에 추적되지 않는 파일 목록이 더해진다.- 인덱스는 파일 경로, 파일 모드, 객체 해시(SHA), 파일 메타데이터(수정 시각, 크기 등)를 기록한다. Git은 이 메타데이터로 변경 여부를 빠르게 판단하고, 필요할 때만 내용을 비교한다.
- 워킹 트리의 수정 내용은
git add전까지 Git 객체로 저장되지 않는다. 따라서 이 상태에서git restore로 덮어쓰면 복구할 방법이 없다.
4. 코드 예제
아래 스크립트는 임시 디렉터리에서 워킹 트리의 상태 변화를 단계별로 확인한다.
shell
#!/bin/zsh
set -e
dir=$(mktemp -d)
cd "$dir"
git init -q
git config user.name "demo"
git config user.email "demo@example.com"
echo "hello" > a.txt
git add a.txt
git commit -qm "init"
# 1) 워킹 트리 수정
echo "world" >> a.txt
echo "new file" > b.txt
echo "--- status (수정 + untracked)"
git status --short
# M a.txt
# ?? b.txt
# 2) 워킹 트리 vs 인덱스 비교
echo "--- diff (unstaged)"
git diff
# 3) 스테이징 후 비교
git add a.txt
echo "--- status (staged)"
git status --short
# M a.txt
# ?? b.txt
echo "--- diff --staged"
git diff --staged
# 4) 워킹 트리 변경 되돌리기
echo "extra" >> a.txt
git restore a.txt # 인덱스 상태로 워킹 트리 복원
cat a.txt # hello, world (스테이징된 내용)
# 5) untracked 파일 정리 (-n: 미리보기)
git clean -n
git clean -f
ls임시로 치워 두는 stash 예제는 다음과 같다.
shell
echo "wip" >> a.txt
git stash # 워킹 트리를 HEAD 상태로 되돌리고 변경 내용을 보관
git status --short # 깨끗함
git stash pop # 보관한 변경을 워킹 트리에 다시 적용5. 시간 복잡도 또는 성능 특성
엄밀한 시간복잡도 표기보다 비용이 어디서 발생하는지를 아는 것이 실용적이다.
git status는 추적 중인 파일 수에 비례해 워킹 트리를 검사한다. 인덱스에 저장된 파일 메타데이터가 같으면 내용을 다시 읽지 않아 대부분의 경우 빠르다.- 파일이 매우 많은 대형 저장소에서는
git status가 느려질 수 있다. 이때 파일 시스템 모니터(core.fsmonitor)나core.untrackedCache같은 설정으로 개선할 수 있다. - 브랜치 전환은 두 커밋 사이에서 달라진 파일만 워킹 트리에서 갱신하므로, 전체 파일을 다시 쓰지 않는다.
6. 실무 사용 사례
- 커밋 전 점검:
git status와git diff로 의도하지 않은 변경이 섞였는지 확인한다. - 부분 커밋:
git add -p로 한 파일 안에서도 원하는 부분만 스테이징한다. - 긴급 작업 전환: 작업 중 급한 버그 수정 요청이 오면
git stash로 워킹 트리를 정리하고 다른 브랜치로 이동한다. - 병행 작업:
git worktree add ../hotfix main으로 별도 디렉터리에 다른 브랜치의 워킹 트리를 만들어, 현재 작업을 건드리지 않고 핫픽스를 진행한다. - 빌드 산출물 제외:
.gitignore에node_modules/,dist/등을 등록해 워킹 트리에 있어도 추적 대상에서 제외한다.
7. 주의할 점
git restore <파일>(또는 구버전의git checkout -- <파일>)과git reset --hard는 커밋하지 않은 워킹 트리 변경을 영구히 지운다. 실행 전에git diff로 확인한다.git clean -f는 untracked 파일을 삭제한다. 반드시git clean -n으로 대상을 먼저 확인한다. 무시된 파일까지 지우려면-x옵션이 필요하므로 더욱 주의한다.git stash는 기본적으로 untracked 파일을 보관하지 않는다. 포함하려면git stash -u를 사용한다..gitignore는 아직 추적되지 않은 파일에만 효과가 있다. 이미 커밋된 파일은git rm --cached <파일>로 추적을 해제해야 한다.- 브랜치를 전환할 때 충돌하는 수정 사항이 있으면 Git이 전환을 거부한다. 먼저 커밋하거나 stash한다.
- 워킹 트리가 깨끗하다(clean)는 것은 추적 중인 파일에 변경이 없다는 뜻이며, untracked 파일은 별도로 확인해야 한다.
8. 핵심 정리
- 워킹 트리는
.git을 제외한, 실제로 편집하는 파일 집합이다. - Git의 세 영역은 워킹 트리, 인덱스(스테이징 영역), 저장소이며 변경은
add와commit을 거쳐 이동한다. git status는 HEAD↔인덱스, 인덱스↔워킹 트리의 차이와 untracked 파일을 보여 준다.- 커밋되지 않은 워킹 트리 변경은 Git 객체로 저장되지 않으므로
restore,reset --hard,clean으로 지우면 복구하기 어렵다. stash와git worktree를 쓰면 작업 중인 상태를 보존한 채 다른 일을 처리할 수 있다.