목차10개 항목
출처와 참고
「브랜치 관리」, 「태그」 부분은 arslanbilal의 「Git and Git Flow Cheat Sheet」와 mingrammer의 「Git Tips」를 바탕으로 보강했다.
브랜치(branch)는 나뭇가지처럼 작업 흐름을 여러 갈래로 나누어 서로 독립적으로 개발할 수 있게 해 주는 기능이다. Git의 브랜치는 특정 커밋을 가리키는 가벼운 포인터일 뿐이라서, 만들고 이동하는 비용이 거의 없다.

왜 브랜치를 쓰는가
- 기본 브랜치(
main)는 보통 배포된 상용 코드를 의미한다. 사용자가 쓰고 있는 코드를 직접 수정하거나 되돌리는 것은 위험하다. - 브랜치를 따로 만들어 그곳에서 기능 개발·버그 수정·실험을 하면 원본은 안전하게 유지된다.
- 작업이 끝나면 그 결과만 원본에 병합하면 된다.
- 하나의 작업 = 하나의 브랜치로 나누면 개발 과정이 체계적이 된다. 한 브랜치에서 여러 기능을 섞어 작업하면, 그중 일부만 먼저 머지해야 할 때 변경을 손으로 다시 나눠야 한다. 기능마다 처음부터 브랜치를 따로 만든다.
HEAD
HEAD는 "지금 내가 있는 브랜치(커밋)"를 가리키는 포인터다. 브랜치를 이동한다는 것은 HEAD가 다른 브랜치를 가리키게 한다는 뜻이고, 그 결과 Working Directory도 그 브랜치의 최신 커밋 상태로 바뀐다.
브랜치 명령어
git branch: 조회·생성·삭제
$ git branch # 로컬 브랜치 목록 (* 표시가 현재 브랜치)
$ git branch -r # 원격 저장소의 브랜치 목록
$ git branch <이름> # 새 브랜치 생성 (이동은 하지 않음)
$ git branch -d <이름> # 병합이 끝난 브랜치 삭제
$ git branch -D <이름> # 강제 삭제 (병합 안 된 브랜치도 삭제, 주의)git switch: 브랜치 이동
Git 2.23(2019)에서 추가된 명령으로, 예전에 git checkout이 하던 일 중 "브랜치 전환" 기능만 분리한 것이다. 파일을 되돌리는 기능은 git restore로 분리되었다.
$ git switch <브랜치> # 다른 브랜치로 이동
$ git switch -c <브랜치> # 새로 만들면서 바로 이동
$ git switch - # 직전 브랜치로 돌아가기
$ git switch -c <브랜치> <시작점> # 다른 브랜치·커밋·태그에서 따서 만들기
$ git switch --detach v1.2.0 # 브랜치 없이 특정 커밋·태그로 (detached HEAD)예전 방식 (checkout) | 새 방식 |
|---|---|
git checkout <브랜치> | git switch <브랜치> |
git checkout -b <브랜치> | git switch -c <브랜치> |
git checkout -- <파일> | git restore <파일> |
git reset HEAD <파일> (스테이징 취소) | git restore --staged <파일> |
git checkout은 지금도 동작하고 Git 프로젝트도 없앨 계획이 없다고 밝혔지만(Git BreakingChanges), 한 명령이 브랜치 이동과 파일 덮어쓰기를 함께 맡아 실수하기 쉽다. 새로 배운다면 switch/restore를 쓰고, 오래된 문서에서 checkout을 보면 위 표처럼 바꿔 읽으면 된다.
예시: 갈라지는 브랜치
main에서 커밋 3개를 만든 뒤 login 브랜치를 만들고, main에 커밋을 하나 더 쌓은 상황이다.
$ git branch login
$ # ... main에서 main-4 커밋 ...
$ git log --oneline
5ca7701 (HEAD -> main) main-4
0604dcd (login) main-3
9c22c89 main-2
3d71510 main-1login으로 이동하면 test.txt에서 main-4 내용이 사라지고, git log에서도 main 브랜치가 보이지 않는다. 브랜치가 지워진 것이 아니라 HEAD 기준으로 이력을 보여주기 때문이다. --all 옵션을 주면 모든 브랜치를 볼 수 있다.
$ git switch login
$ git log --oneline --all
5ca7701 (main) main-4
0604dcd (HEAD -> login) main-3
...login에서 새 커밋을 만들면 두 브랜치가 다른 갈래로 나뉜다.
$ git log --oneline --graph --all
* 3b0a091 (HEAD -> login) login-1
| * 5ca7701 (main) main-4
|/
* 0604dcd main-3
* 9c22c89 main-2
* 3d71510 main-1
브랜치 관리
$ git branch -m <새 이름> # 현재 브랜치 이름 바꾸기 (-m <옛 이름> <새 이름>도 가능)
$ git branch -vv # 각 브랜치의 마지막 커밋과 추적 중인 원격 브랜치, 앞섬·뒤처짐
$ git branch -u origin/<브랜치> # 업스트림(추적 원격 브랜치) 지정
$ git branch --merged main # main에 이미 합쳐진 브랜치 → 지워도 된다
$ git branch --no-merged main # 아직 안 합쳐진 브랜치 → 진행 중인 작업
$ git branch --sort=-committerdate # 최근 커밋 순으로
$ git push origin --delete <브랜치> # 원격 브랜치 삭제
$ git fetch --prune # 원격에서 지워진 브랜치의 origin/* 참조 정리합쳐진 로컬 브랜치를 한 번에 지울 때는 목록을 먼저 눈으로 확인한다.
$ git branch --merged main | grep -vE '^[*+]|^ *main$' # 지울 후보 확인
$ git branch --merged main | grep -vE '^[*+]|^ *main$' | xargs git branch -d-d는 합쳐지지 않은 브랜치를 거부하므로 안전망이 된다. squash나 rebase로 합친 브랜치는 커밋이 달라져 --merged에 잡히지 않으니 직접 -D로 지운다.
이력이 전혀 없는 새 브랜치(문서 사이트용 gh-pages 같은 것)는 git switch --orphan <브랜치>로 만든다.
태그: 움직이지 않는 이름표
브랜치는 새 커밋을 따라 움직이는 포인터이고, 태그(tag)는 한 커밋에 고정된 이름표다. 주로 릴리스 버전(v1.2.0)을 표시한다. 버전 번호 규칙은 유의적 버전(SemVer)에 있다.
| 종류 | 만드는 법 | 담는 것 | 쓰임 |
|---|---|---|---|
| 경량(lightweight) 태그 | git tag v1.2.0 | 커밋 해시만 (브랜치처럼 참조 하나) | 개인용 임시 표시 |
| 주석(annotated) 태그 | git tag -a v1.2.0 -m "Release 1.2.0" | 작성자·날짜·메시지를 담은 태그 객체 | 릴리스에는 이쪽 |
| 서명 태그 | git tag -s v1.2.0 -m "..." | 주석 태그 + GPG/SSH 서명 | 배포물의 출처 검증 |
$ git tag # 목록 (git tag -l "v1.*" 로 패턴 검색)
$ git tag -n # 메시지와 함께
$ git tag -a v1.2.0 <커밋> # 지난 커밋에 나중에 달기
$ git show v1.2.0 # 태그 정보와 커밋
$ git push origin v1.2.0 # 태그는 push에 자동으로 따라가지 않는다
$ git push --follow-tags # 올리는 커밋에 달린 주석 태그만 함께
$ git tag -d v1.2.0 # 로컬 태그 삭제
$ git push origin --delete v1.2.0 # 원격 태그 삭제git push --tags는 로컬의 모든 태그를 올리므로 실험용 태그까지 새어 나간다.--follow-tags(또는 설정push.followTags true)가 안전하다.- 이미 공유한 태그는 옮기지 않는다. 다른 사람의 로컬 태그는 자동으로 바뀌지 않아 같은 이름이 서로 다른 커밋을 가리키게 된다. 잘못 단 릴리스는 새 버전 번호로 다시 낸다.
- 태그를 체크아웃하면 브랜치가 아니므로 detached HEAD가 된다. 그 버전에서 고칠 게 있으면
git switch -c hotfix/1.2.1 v1.2.0처럼 브랜치를 딴다.
주의: 추적되지 않는 파일은 브랜치를 따라다닌다
feature 브랜치에서 test.txt를 만들고 git add 하지 않은 채 git switch main 하면, test.txt가 main에도 그대로 남아 있다.
- 브랜치가 독립적인 것은 Git이 관리하는 파일에 한해서다.
- 한 번도 Staging Area에 올라간 적 없는(untracked) 파일은 버전 관리 대상이 아니므로 브랜치를 바꿔도 Working Directory에 계속 남는다.
- 따라서 브랜치를 옮기기 전에는
git status로 작업 중인 파일이 모두 커밋(또는 정리)됐는지 확인한다.
핵심 정리
- 브랜치 = 커밋을 가리키는 가벼운 포인터, HEAD = 현재 브랜치를 가리키는 포인터.
git switch -c로 만들고 이동, 작업 후 병합, 병합한 브랜치는-d로 삭제.- 이동 전에는 untracked/modified 파일이 없는지 확인한다. 작업을 잠시 치울 때는
stash, 다른 브랜치를 나란히 열 때는worktree(stash, worktree, clean). - 릴리스는 주석 태그로 표시하고, 태그는 따로 push한다.
관련 노트: 브랜치 병합, GitHub 협업 저장소 설정, 브랜치 전략, 작업 중인 변경 다루기: stash, worktree, clean, 유의적 버전(SemVer)