체크아웃
고친 사람 github-actions[bot]
체크아웃은 저장소에 보관된 버전 하나를 꺼내 내가 고칠 수 있는 파일로 펼쳐 줍니다. Git 에서는 따로 쌓아 가는 작업 줄기인 브랜치 사이를 내 컴퓨터 안에서 옮겨 가는 일을 이렇게 부릅니다. 서버 한 곳에 저장소를 두는 도구에서는 작업할 사본을 서버에서 처음 받아 오는 일을 이렇게 부릅니다. 쇼핑몰에서 말하는 체크아웃은 결제 단계를 가리키는 버전관리 밖의 낱말입니다.
쉽고 빠른 이해
무슨 일을 하는 물건인가 — 보관해 둔 코드의 한 모습을 폴더에 펼쳐 줍니다. main 에서 일하다 feature 를 체크아웃하면 폴더 안 파일이 feature 의 내용으로 바뀝니다.
왜 이렇게 하나 — 저장소 안의 버전은 도구가 관리하는 형태라 편집기로 바로 고칠 수 없습니다. 고치려면 버전 하나를 보통 파일로 꺼내 놓아야 합니다.
어떻게 도나 (Git 기준)
- 어느 버전을 꺼낼지 고릅니다. 브랜치 이름을 대거나, 저장소에 쌓인 버전 하나인 커밋을 댑니다
- 폴더의 파일이 그 버전의 내용으로 바뀝니다
- 「지금 이 버전에 있다」는 표시가 그쪽으로 옮겨 갑니다
브랜치 대신 파일 이름을 대면 쓰임이 바뀝니다. 그 파일 하나만 고치기 전 모습으로 되돌립니다.
대가 — 커밋하지 않은 변경이 덮일 수 있습니다. 브랜치를 옮길 때는 덮일 파일이 있으면 Git 이 멈춰서 막아 줍니다. 파일을 되돌릴 때는 묻지 않고 덮습니다.
도구마다 뜻이 달라서 대화가 엇갈리기도 합니다. Subversion 을 쓰던 사람에게 체크아웃은 서버에서 작업할 사본을 처음 받아 오는 일입니다.
상세
이 절은 버전관리에서 「체크아웃」이 가리키는 동작들을 가릅니다.
저장소와 작업 폴더
버전관리 도구는 파일이 바뀌어 온 버전을 차례로 쌓아 둡니다. 쌓아 둔 곳이 저장소입니다. 저장소 안의 버전은 도구가 제 방식으로 묶어 보관합니다. 그래서 편집기로 바로 열어 고칠 수 없습니다.
고치려면 버전 하나를 보통 파일로 꺼내 폴더에 펼쳐 둬야 합니다. Git 은 이 폴더를 작업 트리라고 부릅니다. 또 다른 버전관리 도구인 Subversion 은 같은 폴더를 작업 사본이라고 부릅니다. 이름만 다릅니다. 하는 일은 같습니다.
체크아웃은 저장소에서 이 폴더로 꺼내는 방향의 이름입니다. 반대로 고친 파일을 저장소에 새 버전으로 넣는 일은 커밋입니다. 오래된 도구에서는 이 반대 방향을 체크인이라고 불렀습니다.
도구마다 갈리는 뜻
체크아웃의 뼈대는 도구마다 같습니다. 저장소에서 버전 하나를 꺼내 폴더에 펼칩니다. 어디서 무엇을 꺼내는지는 저장소를 어디에 두느냐에 따라 갈립니다. 이 소절은 저장소를 두는 두 방식을 먼저 보고, 체크아웃의 뜻을 표 하나로 나란히 놓습니다.
첫째 방식은 저장소를 서버 한 곳에만 둡니다. 모두가 같은 서버의 저장소에서 파일을 꺼내 갑니다. 이 방식을 중앙집중식 버전관리라고 합니다. Subversion 이 여기에 듭니다.
둘째 방식은 저장소 전체를 각자의 컴퓨터에 복사해 둡니다. 서버가 멈춰도 내 컴퓨터에서 이력을 보고 커밋할 수 있습니다. 이 방식을 분산 버전관리라고 합니다. Git 이 여기에 듭니다.
그래서 Git 을 쓰면 저장소가 두 벌 생깁니다. 내 컴퓨터에 있는 것이 로컬 저장소입니다. 서버에 두고 여럿이 주고받는 것은 원격 저장소입니다.
| 맥락 | 어디서 꺼내나 | 체크아웃 뒤에 바뀌는 것 | Git 으로 치면 |
|---|---|---|---|
| Git | 내 컴퓨터의 로컬 저장소 | 작업 트리가 다른 브랜치의 모습이 된다 | git checkout |
| Subversion | 서버의 저장소 | 빈 폴더에 작업 사본이 처음 생긴다 | git clone |
| 잠금을 거는 오래된 도구 | 여럿이 함께 쓰는 저장소 | 파일 하나가 내 몫으로 잠긴다 | 기본 명령에는 없다 |
표의 마지막 열이 이 낱말의 함정입니다. Subversion 을 쓰던 사람이 Git 에서 「체크아웃부터 하세요」를 들으면 저장소를 받아 오라는 말로 알아듣습니다. Git 에서 그 일은 클론이 합니다.
Git 과 Subversion 을 가르는 것은 꺼내는 화살표가 어디를 지나느냐입니다. Subversion 의 체크아웃은 서버에서 내 컴퓨터로 네트워크를 건넙니다. Git 의 체크아웃은 내 컴퓨터 안에서 끝납니다. 네트워크를 건너는 일은 클론이 먼저 해 둡니다.
flowchart TD
subgraph 서버
S["Subversion 저장소"]
R["원격 저장소"]
end
subgraph 내컴퓨터["내 컴퓨터"]
W1["작업 사본"]
L["로컬 저장소"]
W2["작업 트리"]
end
S -->|"svn checkout"| W1
R -->|"git clone"| L
L -->|"git checkout"| W2
브랜치 옮기기
브랜치는 커밋이 이어지는 줄기에 붙인 이름입니다. 커밋 하나가 저장소에 쌓인 버전 하나입니다. main 줄기에서 일하다가 새 기능은 feature 줄기에 따로 쌓는 식으로 씁니다.
git checkout feature 를 치면 Git 은 세 가지를 feature 쪽으로 바꿉니다. 셋은 HEAD · 인덱스 · 작업 트리입니다.
| 바뀌는 것 | 무엇인가 | 체크아웃 뒤 |
|---|---|---|
| HEAD | 지금 어느 브랜치에 있는지 가리키는 표지 | feature 를 가리킨다 |
| 인덱스 | 다음 커밋에 넣을 파일을 모아 두는 곳. 스테이징 영역이라고도 부른다 | feature 의 마지막 커밋과 같아진다 |
| 작업 트리 | 내가 편집기로 여는 파일들 | feature 의 마지막 커밋과 같아진다 |
눈으로 보이는 변화는 셋째 줄입니다. version.txt 가 브랜치마다 다른 내용을 가진다고 해 봅시다. 체크아웃 한 번에 같은 파일의 내용이 바뀝니다.
git checkout main
cat version.txt # 1.0
git checkout feature
cat version.txt # 2.0-beta
폴더 경로는 그대로입니다. 안의 내용만 바뀌었습니다. feature 에만 있는 파일은 새로 생깁니다. main 에만 있던 파일은 사라집니다. 체크아웃은 한 폴더를 여러 브랜치의 모습으로 번갈아 바꿔 끼웁니다.
새 브랜치를 만들면서 바로 옮겨 가려면 -b 를 붙입니다. git checkout -b fix 는 지금 커밋에서 fix 브랜치를 만듭니다. 그리고 HEAD 를 거기로 옮깁니다. 새 브랜치가 지금 커밋에서 출발하므로 작업 트리의 파일은 바뀌지 않습니다.
커밋하지 않은 변경이 있을 때
고치던 파일이 있는 채로 체크아웃하면 Git 은 먼저 그 변경이 덮이는지 봅니다. 고친 파일이 두 브랜치에서 내용이 같으면 변경을 들고 옮겨 갑니다. 두 브랜치에서 내용이 다르면 체크아웃을 거부하고 멈춥니다.
flowchart TD
A["git checkout feature"] --> B{"고치던 파일이 있나"}
B -->|없다| C["feature 로 옮긴다"]
B -->|있다| D{"그 파일이 두 브랜치에서 같은가"}
D -->|같다| E["변경을 들고 feature 로 옮긴다"]
D -->|다르다| F["거부하고 멈춘다"]
멈추는 까닭은 커밋하지 않은 변경이 저장소 어디에도 없기 때문입니다. 덮어 쓰면 되살릴 길이 없습니다.
이럴 때 쓰는 것이 스태시입니다. 스태시는 고치던 내용을 따로 보관했다가 나중에 꺼내 다시 붙이는 기능입니다. 변경을 커밋하거나 스태시로 치워 둔 뒤 다시 체크아웃하면 됩니다.
커밋으로 옮기기
체크아웃에는 브랜치 이름 대신 커밋을 댈 수도 있습니다. 커밋마다 붙는 고유 번호인 커밋 해시를 적습니다. 그러면 작업 트리가 그 커밋 때의 모습으로 돌아갑니다. 옛 버전에도 버그가 있었는지 확인할 때 씁니다.
이때 HEAD 는 브랜치가 아니라 커밋을 곧장 가리킵니다. 이 상태를 분리된 HEAD라고 부릅니다. 둘러보기만 할 때는 문제가 없습니다.
분리된 HEAD 에서 새 커밋을 만들면 그 커밋은 어느 브랜치에도 안 붙습니다. 다른 브랜치로 옮겨 가면 이름 없이 남아 다시 찾기 어려워집니다. 그 커밋을 남기려면 떠나기 전에 git checkout -b 이름 으로 브랜치를 만들어 붙입니다.
파일 되돌리기
git checkout 은 브랜치가 아니라 파일 하나를 대상으로도 씁니다. 파일 이름을 대면 작업 트리의 그 파일을 인덱스의 내용으로 덮어 씁니다. 인덱스에 따로 모아 둔 것이 없으면 덮어 쓰는 내용은 마지막 커밋의 것입니다.
아래는 고치던 app.py 를 되돌리는 모습입니다. 첫 줄의 M 은 그 파일이 고쳐졌다는 표시입니다.
git status --short # M app.py
git checkout -- app.py
git status --short # (출력 없음)
둘째 줄의 -- 는 뒤에 오는 것이 파일 이름이라는 표시입니다. 브랜치와 파일의 이름이 같을 때 Git 이 헷갈리지 않게 해 줍니다. 셋째 줄에서는 고친 흔적이 사라졌습니다.
이 쓰임은 브랜치 옮기기와 안전장치가 반대입니다. 브랜치를 옮길 때는 덮일 변경이 있으면 멈췄습니다. 파일을 되돌릴 때는 묻지 않고 덮습니다. 버린 내용은 커밋한 적이 없어서 Git 으로 되살릴 수 없습니다.
switch 와 restore
한 명령이 안전장치가 반대인 두 일을 맡으면 헷갈리기 쉽습니다. 그래서 뒤에 나온 Git 은 두 일을 새 명령 둘로 나눠 두었습니다. git switch 는 브랜치 옮기기만 합니다. git restore 는 파일 되돌리기만 합니다.
| 하려는 일 | git checkout 으로 |
새 명령으로 |
|---|---|---|
| 브랜치로 옮기기 | git checkout feature |
git switch feature |
| 브랜치를 만들며 옮기기 | git checkout -b fix |
git switch -c fix |
| 파일 되돌리기 | git checkout -- app.py |
git restore app.py |
git checkout 도 없어지지 않고 계속 동작합니다. 대화에서 「main 을 체크아웃한다」고 하면 명령과 상관없이 main 브랜치로 옮긴다는 뜻입니다.
Subversion 의 체크아웃
Subversion 에서 체크아웃은 작업을 시작할 때 한 번 하는 일입니다. 서버에 있는 저장소의 주소를 대면 빈 폴더에 작업 사본이 생깁니다.
svn checkout http://svn.example.com/repos/calc
ls calc # Makefile button.c integer.c
작업 사본에는 파일과 그 파일이 어느 버전에서 왔는지 정도가 들어 있습니다. 지난 이력은 서버에만 있습니다. 그래서 새 버전을 받을 때는 svn update 로 서버에 묻습니다. 고친 것은 svn commit 으로 서버에 바로 올립니다.
Subversion 에서 다른 브랜치로 옮겨 가는 명령은 따로 있습니다. svn switch 입니다. 짝을 지으면 Subversion 의 체크아웃은 Git 의 클론에 가깝습니다. Git 의 체크아웃은 Subversion 의 switch 에 가깝습니다.
클론 안에 든 체크아웃
Git 의 클론은 원격 저장소를 통째로 복사해 로컬 저장소를 만듭니다. 복사가 끝나면 기본 브랜치를 한 번 체크아웃해 작업 트리를 채웁니다. Git 에서도 클론 한 번 안에 체크아웃이 들어 있는 셈입니다.
지속적 통합은 코드가 올라올 때마다 빌드와 시험을 자동으로 돌리는 방식입니다. 이 일을 맡은 빌드 서버도 클론과 체크아웃을 차례로 합니다. 저장소를 받아 빌드할 커밋을 펼친 뒤에야 빌드를 시작할 수 있습니다.
그래서 빌드 설정에는 대개 checkout 이라는 단계가 맨 앞에 들어갑니다. GitHub Actions 의 actions/checkout 이 그런 단계입니다. 이름은 체크아웃이지만 클론까지 함께 합니다.
잠금을 거는 체크아웃
RCS(Revision Control System) 같은 오래된 도구는 체크아웃에 잠금을 붙였습니다. 파일 하나를 고치겠다고 저장소에서 꺼내면 그 파일이 내 몫으로 잠깁니다. 다른 사람은 내가 체크인할 때까지 그 파일을 고치지 못합니다.
이 방식은 두 사람이 한 파일을 동시에 고치는 일을 처음부터 막습니다. 나중에 두 변경을 합치는 병합이 필요 없어집니다. 대가는 기다림입니다. 누가 파일을 체크아웃해 둔 채 퇴근하면 나머지는 그 파일을 못 고칩니다.
Git 에는 이런 잠금이 기본으로 없습니다. 각자 자기 작업 트리에서 고친 뒤 나중에 병합합니다.
어느 뜻인지 가르는 단서
대화나 문서에서 「체크아웃」이 나오면 함께 붙은 낱말을 봅니다. 대개 그것만으로 어느 뜻인지 갈립니다.
| 함께 나오는 말 | 뜻 |
|---|---|
브랜치 이름 · git checkout · 「main 으로 체크아웃」 |
Git 의 브랜치 옮기기 |
| 커밋 해시 · 「옛 커밋을 체크아웃」 · 분리된 HEAD | Git 의 커밋으로 옮기기 |
빌드 설정의 checkout 단계(actions/checkout 등) |
빌드 서버가 저장소를 받아 그 커밋을 펼친다. 클론과 체크아웃을 한 번에 한다 |
저장소 주소 · svn checkout · 작업 사본 |
Subversion 에서 작업 사본을 처음 받아 오기 |
| 체크인 · 잠금 · 「누가 체크아웃해 둬서 못 고친다」 | 잠금을 거는 체크아웃 |
| 장바구니 · 결제 · 주문 | 쇼핑몰의 결제 단계. 버전관리와 상관없다 |
관련 항목
체크아웃이 버전을 꺼내 오는 저장소
저장소 · 로컬 저장소 · 원격 저장소 · 중앙 저장소 · 베어 저장소
체크아웃이 바꾸는 Git 의 구성 요소
작업 트리 · HEAD (Git) · 스테이징 영역 · 브랜치 · 커밋 · 커밋 해시 · 분리된 HEAD
체크아웃과 앞뒤로 쓰는 Git 명령
클론 · 페치 · 풀 · 푸시 · 병합 · 리베이스 · 스태시 · 리셋 · 체리픽
체크아웃을 대신하거나 넓히는 Git 명령
git switch · git restore · 희소 체크아웃 · git worktree
체크아웃이 뜻을 달리하는 버전관리 방식
버전관리 · Git · Subversion · CVS · 중앙집중식 버전관리 · 분산 버전관리 · 작업 사본
체크아웃과 동시 수정을 다루는 방식
체크인 · 파일 잠금 · 잠금-수정-해제 · 복사-수정-병합 · 병합 충돌
체크아웃 단계를 자동으로 부르는 빌드 도구
지속적 통합 · 빌드 파이프라인 · GitHub Actions
쇼핑몰에서 체크아웃이 가리키는 결제 절차
결제 · 장바구니 · 전자상거래
다른 이름: checkout · git checkout · svn checkout