git checkout
2023. 6. 28. 17:01ㆍGit
git checkout
명령어는 단순한 브랜치 전환 이상의 복합적인 Git 내부 작업을 수행하며, Git의 워킹 디렉토리, 인덱스(Index), HEAD, 그리고 리퍼런스(refs) 사이의 동작 원리를 이해해야만 그 진면목을 파악할 수 있습니다.
✅ 개요: git checkout은 무엇인가?
git checkout
은 Git에서 HEAD 포인터를 이동하거나, 특정 커밋 또는 브랜치의 스냅샷을 워킹 디렉토리에 복원하는 데 사용됩니다. 이것은 다음과 같은 두 가지 유형의 동작으로 구분됩니다:
- 브랜치 기반 checkout:
HEAD
포인터를 다른 브랜치로 이동하고, 그 브랜치가 가리키는 커밋을 워킹 디렉토리와 인덱스에 반영합니다. - 파일/트리 기반 checkout: 특정 커밋이나 브랜치로부터 특정 파일이나 디렉토리를 선택적으로 복원합니다. HEAD는 바뀌지 않습니다.
🧠 Git 내부의 세 가지 핵심 개체
Git은 다음의 세 구조 사이를 오가며 작업합니다:
HEAD ---------> 커밋 (브랜치 또는 해시)
|
| git checkout은 이 세 가지에 영향을 미친다
v
Index (스테이징 영역)
|
v
Working Directory (작업 디렉토리)
🧱 내부 동작 구조 해부
1️⃣ 브랜치 전환: git checkout <branch>
🔹 수행 작업
HEAD
→<branch>
로 변경- 인덱스(index) ←
<branch>
가 가리키는 커밋의 트리로 초기화 - 워킹 디렉토리 ← 인덱스와 동일하게 복원
🔍 내부적으로는 다음 순서로 진행:
[1] HEAD 이동 : HEAD → refs/heads/<branch>
[2] Index 초기화 : Index ← Tree(<branch>)
[3] Working Directory : 파일 변경/삭제/추가 → Tree와 동기화
💥 실패 조건
- 현재 작업 디렉토리 또는 인덱스에 uncommitted 변경 사항이 존재하고, 그것이 새 브랜치의 상태와 충돌할 경우 checkout 실패
2️⃣ 새 브랜치 생성 후 전환: git checkout -b <new-branch> [<start-point>]
🔹 내부 동작
refs/heads/<new-branch>
생성 →<start-point>
커밋을 가리킴- HEAD →
<new-branch>
- index, working directory ←
<start-point>
트리
start-point
는 생략 시 HEAD가 가리키는 커밋을 기본값으로 사용
3️⃣ 특정 커밋/브랜치 기준으로 파일 복원: git checkout <commit-ish> -- <path>
🔹 수행 작업
<commit-ish>
는 커밋 해시, 브랜치명, 태그명, HEAD, HEAD~n 등 모두 가능- 해당 커밋의 트리에서 지정된
<path>
파일만 가져와서:- 인덱스(index) 업데이트
- 워킹 디렉토리 덮어쓰기
🔍 내부적 흐름
[1] 지정 커밋의 트리에서 <path> 파일 읽기
[2] Index ← 덮어쓰기
[3] Working Directory ← 덮어쓰기
HEAD
포인터는 이동하지 않음
전체 트리를 덮어쓰는 것이 아니라 선택적 파일 복원임
4️⃣ 특정 커밋으로 HEAD를 직접 이동: git checkout <commit-hash>
🔹 결과: Detached HEAD 상태
- HEAD가 브랜치를 참조하지 않고, 커밋 해시를 직접 가리킴
- 이후 커밋은 브랜치가 아닌 "익명 체인"으로 생성됨
$ git checkout 9fceb02
# HEAD now points to 9fceb02 (detached HEAD)
🔎 내부 동작
HEAD → 9fceb02 (커밋 해시)
Index ← Tree(9fceb02)
Working Directory ← Tree(9fceb02)
❗ 이 상태에서 커밋한 내용은 브랜치에 연결되지 않으며, 브랜치 생성 없이 checkout하거나 reset하면 유실 위험
5️⃣ 강제 checkout: git checkout -f <branch>
-f
또는--force
옵션은 변경 사항이 있어도 강제로 워킹 디렉토리와 인덱스를 덮어씀- 매우 위험하며, 실제 파일이 사라질 수 있음
📁 실전 예제 정리
명령어 | 의미 |
---|---|
git checkout main |
main 브랜치로 HEAD 이동 |
git checkout -b dev |
새 브랜치 dev 생성 및 전환 |
git checkout HEAD~1 -- src/App.java |
한 커밋 전의 App.java 복원 |
git checkout -- README.md |
마지막 커밋 기준으로 README.md 복원 |
git checkout 9fceb02 |
해당 커밋으로 Detached HEAD 전환 |
git checkout -f feature/test |
강제로 feature/test 브랜치로 전환 |
🧬 git checkout
vs git switch
/ git restore
Git 2.23 이상에서는 명령의 목적을 분리하기 위해 다음과 같은 명령어로 대체 가능:
목적 | 예전 | 현재 권장 |
---|---|---|
브랜치 전환 | git checkout main |
git switch main |
브랜치 생성 | git checkout -b feat |
git switch -c feat |
파일 복원 | git checkout HEAD -- file |
git restore file |
git checkout
은 백워드 호환을 위해 여전히 존재하지만 기능이 지나치게 많고 오류 발생 여지가 높기 때문에 분리 권장
⚙️ 내부 설정 파일과 연관
HEAD
파일
.git/HEAD
는 현재 브랜치 또는 커밋 해시를 가리킴
ref: refs/heads/main
또는 Detached 상태에서는:
9fceb02c3a0db56a786f4e8ebd4eacf1c69c3251
🧷 실수 방지를 위한 전문가 팁
상황 | 대응 전략 |
---|---|
checkout 시 변경사항 충돌 | git stash , git commit , git restore 로 해결 |
Detached HEAD 상태로 실수 | git switch -c recovery-branch 로 브랜치 생성하여 복구 |
브랜치 전환 안전하게 수행 | git switch 권장 |
특정 파일만 복원 시 | git restore 사용 |
📌 결론
git checkout
은 HEAD, index, working directory 세 곳을 동시에 조작하는 복합적 명령- 브랜치 전환, 커밋 전환, 파일 복원이라는 세 가지 역할을 수행
- 사용이 편리하지만, 위험성과 복잡성이 있어서 최신 Git에서는
switch
,restore
로 분리됨 - Git 내부 구조와 연동된 HEAD, refs, 트리 객체, 인덱스를 완전히 이해해야 의도하지 않은 데이터 유실을 방지할 수 있음
'Git' 카테고리의 다른 글
recursive merge strategy (0) | 2023.06.28 |
---|---|
ort merge strategy (0) | 2023.06.28 |
git rebase 시, --continue 옵션 사용 (0) | 2023.06.28 |
merge class : index.html (0) | 2023.06.26 |
Detached HEAD (0) | 2023.06.26 |