개발하면서 기능을 구현하고 커밋할때마다 '이 기능은 제대로 구현하지 못했는데 커밋해도 되는걸까?'라는 생각이 들었습니다. Git Branch를 사용하면 main 브랜치에 검증된 코드들만 커밋할 수 있고, 동시 다발적으로 기능 개발을 할 수 있습니다. Git을 조금 더 편라하고 유용하게 사용할 수 있는 Git Branch에 대해 자세히 알아보고 알기 쉽게 정리해보려 합니다.
Git의 브랜치는 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것이다. (Git Book)
Git이 브랜치를 다루는 과정을 이해하려면 우선 Git이 데이터를 어떻게 저장하는지 알아야 합니다.
Git은 데이터를 스냅샷의 스트림처럼 취급합니다. 다시 말해, Git은 데이터를 파일 시스템 스냅샷의 연속으로 취급하고 크기가 아주 작습니다. Git은 커밋하거나 프로젝트의 상태를 저장할 때마다 파일이 존재하는 그 순간을 중요하게 여깁니다. 파일이 달라지지 않았으면 Git은 성능을 위해서 파일을 새로 저장하지 않습니다.
커밋하면 Git은 커밋 객체(Commit Object)를 저장합니다. 커밋 객체는 현 Staging Area에 있는 데이터 스냅샷에 대한 포인터, 저자나 커밋 메시지 같은 메타데이터, 이전 커밋에 대한 포인터 등을 포함합니다. 커밋 객체에 이전 커밋에 대한 포인터가 있기 때문에 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있습니다.
Git의 브랜치는 커밋 사이를 가볍게 이동할 수 있는 포인터 같은 것입니다. 기본적으로 Git은 main
브랜치를 만듭니다. 처음 커밋하면 이 main
브랜치가 생성된 커밋을 가리킵니다. 이후 커밋을 만들면 main
브랜치는 자동으로 가장 마지막 커밋(가장 최근 커밋)을 가리킵니다.
main
브랜치에는 기능에 문제가 없고 정확하게 검증딘 코드들만 포함되어야 합니다. 브랜치는 검증을 마친 코드들만 main
브랜치에 merge 할 수 있습니다.$ git branch testing
git branch
명령어로 testing
이라는 이름을 가진 브랜치를 새로 생성할 수 있습니다.git branch
명령은 브랜치를 만들기만 하고 브랜치를 옮기지 않습니다.$ git chaeckout testing
$ git switch testing
git checkout
이나 git switch
로 testing
브랜치로 이동할 수 있습니다.testing
브랜치를 가리킵니다.$ git commit -a -m 'made a change'
$ git checkout main
testing
브랜치는 새로운 커밋을 가리키고 main
브랜치는 계속 이전 커밋을 가리킵니다.main
브랜치로 돌아옵니다. 따라서 'HEAD'는 main
브랜치를 가리킵니다.main
브랜치가 가리키는 커밋을 'HEAD'가 가리키게 하고 워킹 디렉토리의 파일도 그 시점으로 되돌려 놓았습니다.testing
브랜치에서 임시로 작업하고 원래 main
브랜치로 돌아와서 하던 일을 계속할 수 있습니다.$ git commit -a -m 'made other changes'
main
브랜치에서 파일을 수정하고 커밋했기 때문에 이전에 수정한 내용은 다른 브랜치(testing
)에 존재합니다.$ git checkout -b testing
$ git swtich -C testing
git checkout -b
와 git switch -C
명령어로 새로운 브랜치를 생성하고 해당 브랜치로 이동할 수 있습니다.(1) 로컬 브랜치 확인
$ git branch
iss53
* master
testing
git branch
명령어로 현재 레포지터리에 있는 브랜치를 확인할 수 있습니다.*
기호기 붙은 브랜치는 현재 Checkout 해서 작업하는 브랜치를 나타냅니다.(2) 브랜치와 커밋 메시지 확인
$ git branch -v
iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
testing 782fd34 add scott to the author list in the readmes
git branch -v
명령어로 브랜치와 함께 최신 커밋 메시지를 확인할 수 있습니다.(3) 원격 브랜치 확인
$ git branch --all
git branch --all
명령어로 원격 서버에 있는 모든 브랜치를 확인할 수 있습니다.$ git branch --merged
iss53
* master
git branch --merged
명령어로 현재 브랜치에 머지된 브랜치를 확인할 수 있습니다.iss53
브랜치는 앞에서 이미 merge 했기 때문에 목록에 나타납니다.*
기호가 붙어 있지 않은 브랜치는 이미 다른 브랜치와 merge 했기 때문에 git branch -d
명령으로 삭제해도 되는 브랜치 입니다.$ git branch --no-merged
testing
git branch --no-merged
명령어로 현재 브랜치에 머지되지 않은 브랜치를 확인할 수 있습니다.testing
브랜치는 git branch -d
명령으로 삭제되지 않습니다.$ git branch -d testing
git branch -d
명령어로 testing
브랜치를 삭제할 수 있습니다.$ git push origin --delete testing
git branch -d
명령어로 브랜치를 삭제했다면 원격 저장소에 업데이트해야 합니다. git push origin --delete
명령어로 원격 저장소의 브랜치를 삭제할 수 있습니다.$ git branch --move testingA testingB
git branch --move
명령어로 브랜치 이름을 testingA
에서 testingB
로 변경할 수 있습니다.$ git push --set-upstream origin testingB
git push --set-upstream origin
명령어로 변경된 브랜치를 push 합니다.그림으로 Rebase의 과정을 자세히 살펴보겠습니다.
c
에서 새로운 브랜치인 new_branch가 생성되었습니다.f
가 생겼습니다.g
를 만들어 main 브랜치에 merge 하였습니다.d
와 e
를 main 브랜치의 새로운 커밋인 f
로 포인터(HEAD)를 옮기는 것을 말합니다.f
로 옮겨진 d
와 e
는 기존의 커밋이 아니라 새롭게 만들어진 커밋입니다. f
이후에는 변동 사항이 없습니다. 그래서 c
에 있던 포인터를 e
로 옮기고 new-branch를 삭제합니다.위의 Rebase 과정을 코드로 살펴보겠습니다.
$ git checkout new-branch
$ git rebase main
$ git checkout main
$ git merge new-branch
$ git branch -d new-branch
d
와 e
는 새롭게 생성됩니다. 그렇기 때문에 다른 개발자가 가지고 있는 d
와 e
와는 완전히 다른 커밋이 됩니다. 이는 나중에 머지 충돌을 발생시킬 위험이 있습니다.rebase --onto
로 브랜치 위에 새로운 브랜치들이 체이닝 되어 있을 때 쉽게 머지할 수 있습니다.
그림으로 더 자세히 살펴보겠습니다.
c
에서 새로운 브랜치인 server 브랜치를 만들고, 그 브랜치에서 client 브랜치를 만들었습니다.rebase --onto
를 사용할 수 있습니다.rebase --onto
로 client 브랜치를 main 브랜치에 머지하였습니다.g
와 h
커밋은 기존의 커밋이 아니라 새롭게 생긴 커밋입니다.코드로 작성하면 아래와 같습니다.
git rebase --onto main server client
git rebase --onto
명령어로 client 브랜치를 server 브랜치 없이 main 브랜치에 머지하였습니다.마지막으로 살펴볼 것은 cherry pick
입니다. cherry pick
을 사용하면 필요한 커밋만 main 브랜치로 가져올 수 있습니다.
그림으로 더 자세히 살펴보겠습니다.
cherry pick
으로 server
브랜치의 e
커밋을 main
브랜치로 가져올 수 있습니다.코드로 작성하면 아래와 같습니다.
$ git cherry-pick '해시코드'
main
브랜치로 가져올 커밋의 해시코드를 복사하고 git cherry-pick
명령어로 해당 커밋을 main
브랜치로 가져옵니다.출처