본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Tools

Git 브랜치

추가
목차10개 항목
출처와 참고

「브랜치 관리」, 「태그」 부분은 arslanbilal의 「Git and Git Flow Cheat Sheet」와 mingrammer의 「Git Tips」를 바탕으로 보강했다.

브랜치(branch)는 나뭇가지처럼 작업 흐름을 여러 갈래로 나누어 서로 독립적으로 개발할 수 있게 해 주는 기능이다. Git의 브랜치는 특정 커밋을 가리키는 가벼운 포인터일 뿐이라서, 만들고 이동하는 비용이 거의 없다.

브랜치 개념

왜 브랜치를 쓰는가

  • 기본 브랜치(main)는 보통 배포된 상용 코드를 의미한다. 사용자가 쓰고 있는 코드를 직접 수정하거나 되돌리는 것은 위험하다.
  • 브랜치를 따로 만들어 그곳에서 기능 개발·버그 수정·실험을 하면 원본은 안전하게 유지된다.
  • 작업이 끝나면 그 결과만 원본에 병합하면 된다.
  • 하나의 작업 = 하나의 브랜치로 나누면 개발 과정이 체계적이 된다. 한 브랜치에서 여러 기능을 섞어 작업하면, 그중 일부만 먼저 머지해야 할 때 변경을 손으로 다시 나눠야 한다. 기능마다 처음부터 브랜치를 따로 만든다.

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-1

login으로 이동하면 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)

원본 기록4

댓글

GitHub 계정으로 댓글을 남길 수 있어요.