73.1 브랜치가 왜 필요해요?
혼자 조용히 작업할 땐 커밋을 쭉 쌓기만 하면 돼요. 그런데 실무는 좀 달라요. "로그인 기능"을 한창 만드는 중에 갑자기 급한 버그를 고쳐야 한다면요? 반쯤 만든 로그인 코드에 버그 수정을 막 섞으면 둘 다 엉망이 되죠.
이럴 때 쓰는 게 브랜치(branch, 가지)예요. 브랜치는 지금 코드에서 갈라져 나온 독립된 작업 공간이에요. 로그인은 로그인 브랜치에서, 버그 수정은 또 다른 브랜치에서 따로따로 작업하면 서로 안 섞여요.
기본으로 쓰는 줄기는 보통 main이라고 불러요. 여기서 가지를 쳐서 작업하고, 다 되면 다시 main으로 합치는 게 실무의 기본 흐름이에요.
73.2 브랜치는 어떻게 만들어요?
지금 있는 브랜치 목록은 git branch로 봐요.
$ git branch
* main
별표(*)가 붙은 게 지금 내가 있는 브랜치예요. 새 브랜치를 만들려면 뒤에 이름을 붙여줘요.
$ git branch feature-login
$ git branch
feature-login
* main
feature-login이 생겼는데, 별표는 아직 main에 있죠? 만들기만 했지 그리로 옮겨간 건 아니에요. 브랜치를 옮겨 타려면 git switch를 써요.
$ git switch feature-login
Switched to branch 'feature-login'
이제 별표가 feature-login으로 옮겨갔어요. 만들면서 동시에 옮겨가고 싶으면 -c 옵션 하나로 한 번에 끝나요. 실무에선 이걸 훨씬 많이 써요.
$ git switch -c feature-signup
Switched to a new branch 'feature-signup'
73.3 브랜치에서 커밋하면 어떻게 되나요?
feature-signup 브랜치에서 signup.py를 만들고 커밋해볼게요.
$ git add signup.py
$ git commit -m "feat: add signup page"
[feature-signup b745a2d] feat: add signup page
1 file changed, 2 insertions(+)
이 커밋은 feature-signup에만 쌓였어요. 정말 그런지 그림처럼 확인해볼까요?
$ git log --oneline --all --decorate
b745a2d (HEAD -> feature-signup) feat: add signup page
d4cd177 (main, feature-login) chore: add readme, gitignore, update hello
67c59b4 feat: add bye function
06da621 feat: add hello function
괄호를 보세요. signup 커밋 위엔 feature-signup만 서 있고, main과 feature-login은 그 아래 커밋에 그대로 머물러 있죠. --all은 모든 브랜치를, --decorate는 어느 브랜치가 어디 있는지 이름표를 같이 보여줘요.
실제로 main으로 돌아가 보면 signup.py가 아예 없어요.
$ git switch main
$ ls
app.log app.py README.md secret.txt
signup.py가 안 보이죠? 브랜치를 바꾸면 폴더 안 파일들도 그 브랜치 상태로 싹 바뀌어요. 다른 브랜치 작업물이 내 눈앞에서 사라졌다가, 그리로 돌아가면 다시 나타나요. 이게 브랜치들이 서로 안 섞이는 비결이에요.
73.4 브랜치를 빠르게 오가려면요?
작업하다 보면 main과 내 브랜치를 하루에도 수십 번 오가요. 그때마다 긴 이름을 다 치기 번거롭죠. 이럴 땐 git switch - 하나로 바로 직전에 있던 브랜치로 되돌아갈 수 있어요.
$ git switch feature/login
Switched to branch 'feature/login'
$ git switch main
Switched to branch 'main'
$ git switch -
Switched to branch 'feature/login'
마지막 줄을 보면 이름을 안 쳤는데도 방금 전 브랜치인 feature/login으로 돌아갔죠. main과 작업 브랜치를 왔다 갔다 할 때 정말 편해요.
그리고 각 브랜치가 지금 어느 커밋에 서 있는지 한눈에 보고 싶으면 git branch -v를 써요.
$ git branch -v
* feature/login d4cd177 chore: add readme, gitignore, update hello
main d4cd177 chore: add readme, gitignore, update hello
브랜치 이름 옆에 그 브랜치의 최신 커밋 번호와 메시지가 같이 나와요. -v는 자세히(verbose) 보여준다는 뜻이에요. 참고로 예전엔 브랜치 이동에 git checkout을 썼는데, 요즘은 뜻이 더 분명한 git switch를 권해요. 옛날 자료에서 checkout이 나와도 당황할 필요 없어요.
73.5 다 쓴 브랜치는 어떻게 정리해요?
작업이 끝나 main에 합친 브랜치는 지워서 깔끔하게 정리해요. 지워도 되는지 헷갈리면 git branch --merged로 "지금 브랜치에 이미 합쳐진 브랜치들"만 추려볼 수 있어요. 여기 뜨는 건 지워도 안전하다는 뜻이에요.
$ git branch --merged
feature/login
* main
목록에 나온 브랜치는 git branch -d로 지워요. 그런데 아직 합치지 않은 브랜치를 지우려 하면 Git이 막아서요.
$ git branch -d feature-signup
error: the branch 'feature-signup' is not fully merged
hint: If you are sure ... run 'git branch -D feature-signup'
"이 브랜치 아직 어디에도 안 합쳤는데 진짜 지울 거야?"라고 되묻는 거예요. 지우면 그 안의 커밋들이 통째로 날아갈 수 있으니 안전장치를 둔 거죠. 정말 버릴 거면 대문자 -D로 강제 삭제해요.
$ git branch -D feature-signup
Deleted branch feature-signup (was b745a2d)
지우는 게 아니라 이름만 바꾸고 싶을 땐 -m이에요. 예를 들어 feature-login을 feature/login으로 바꿔볼게요.
$ git branch -m feature-login feature/login
73.6 오늘 배운 걸 정리해볼게요
브랜치는 지금 코드에서 갈라져 나온 독립 작업 공간이에요. git branch로 목록을 보고, git switch -c 이름으로 만들면서 바로 옮겨가요. 커밋은 지금 서 있는 브랜치에만 쌓이고, 브랜치를 바꾸면 파일도 그 상태로 바뀌어요.
정리는 -d(안전 삭제)와 -D(강제 삭제), 이름 변경은 -m이에요. 오갈 땐 git switch -가 편하고, 상태 확인은 git branch -v고요. main에서 가지를 쳐서 따로 작업하다가 나중에 하나로 합치는 흐름, 이게 실무 협업의 뼈대예요. 이제 그 합치는 방법을 제대로 익힐 차례고요.