저번 시간에는 변경 사항을 하나의 버전으로 저장하는 커밋을 다루는 방법에 대해 자세히 알아봤습니다.

이번 시간에는 Git에서 중요한 작업 중 하나인 branch에 대해 함께 알아보겠습니다.

🌱 브랜치(Branch)

브랜치는 나뭇가지라는 뜻의 단어인데요. Git에서의 브랜치는 하나의 코드 관리 흐름이라는 의미를 가지고 있습니다.

git의 로고를 자세히 들여다보면 나뭇가지와 같은 모양을 확인할 수 있습니다. 나무는 하나의 뿌리에서 여러 가지로 나누어지죠? Git도 마찬가지입니다.

앞서 맨 처음 진행한 커밋을 'root commit'이라 부른다고 배웠습니다. root는 뿌리라는 의미를 가집니다. Git은 이 루트 커밋을 시작으로 가지가 나눠지는 나무 모양을 하고 있습니다. 이때, 가지 하나하나를 브랜치라고 합니다.

프로젝트를 진행하다 보면 딱 하나의 코드 관리 흐름으로만 순조롭게 진행할 수 있는 경우는 드뭅니다. 대개는 버전을 나누어 개발을 진행하곤 하죠. 예를 들어, 무료 버전과 유료 버전을 나눈다고 합시다. 무료 버전과 유료 버전은 큰 차이가 없습니다. 보통 무료 버전에 추가 기능을 적용한 것을 유료 버전으로 출시하곤 하죠.

이 경우, 두 개의 서로 다른 프로젝트를 진행하기 보다는 하나의 프로젝트 내에서 브랜치 두 개를 만드는 것이 효율적입니다. 하나의 프로젝트에 두 개의 버전을 만드는 거죠.

지금까지 우리는 하나의 브랜치에서 작업을 진행했습니다.

git status 커맨드 아래에 On branch master라는 문구가 보이시나요? 이 문구는 말그대로 현재 작업이 master라는 브랜치 위에 있다는 뜻입니다. master는 레포지토리를 만들고 커밋을 하면 자동으로 생기는 브랜치입니다. Git으로 작업을 진행하면 기본으로 세팅되는 브랜치인 거죠.

커밋 히스토리에 나타나는 위 커밋들은 모두 하나의 코드 관리 흐름에서 진행된 것입니다. 즉, 하나의 브랜치에서 이루어진 작업들이라고 할 수 있죠.

지금부터는 master에서 이루어진 작업들을 무료 버전을 위한 작업이라고 하겠습니다. 그리고 이 프로젝트의 유료 버전을 위한 브랜치 premium을 새로 하나 만들겠습니다.

git branch [브랜치 이름]

이렇게 하면 이때까지 작업했던 모든 내용이 반영된 새로운 브랜치 premium이 생성됩니다.

브랜치를 생성한 다음 가장 먼저 해야할 일은 생성된 브랜치로 이동하는 것입니다.

git checkout [브랜치 이름]

그럼 premium 브랜치로 이동합니다. 현재 상태를 봅시다.

아까와는 달리 premium 브랜치 위에 있다는 On branch premium 문구가 뜹니다. 눈썰미가 좋다면 이미 아셨겠지만 경로 옆 괄호 안의 내용도 master에서 premium으로 바뀌었습니다. 이 상태로 작업을 하면 지금부터의 내용은 모두 premium 브랜치에만 반영됩니다. 그리고 그 커밋들은 이제 master 브랜치와는 아무런 상관이 없게 됩니다.

본격적으로 유료 버전을 만들어보도록 하죠. 지난 시간에 생성한 License 파일을 열어주세요. Free라는 문구가 적혀있을 텐데요. 모두 지운 뒤 Premium이라는 문구를 적어줍시다. 저장까지 해주세요.

staging area에 올리고 커밋까지 완료했습니다. 커밋 메시지로는 Change License from free to premium이라고 적어주었습니다. 다음으로 premium 브랜치에 위치한 상태에서 License의 내용을 출력해보겠습니다.

cat License


그럼 수정된 내용대로 Premium이라는 문구가 출력됩니다.

차이를 확인하기 위해 master 브랜치로 돌아간 후, License 파일을 출력해보겠습니다.

git checkout master
cat License

그럼 원래 License 내용대로 Free라는 문구가 출력됩니다. 즉, master 브랜치에는 수정된 내용이 반영되지 않았다는 거죠.

이렇게 우리가 작업하고 있는 프로젝트는 premium 브랜치 생성을 기점으로 유료 버전과 무료 버전으로 나눠졌습니다. 마치 하나의 나무로부터 갈라진 두 나뭇가지처럼 말이죠. 유료 버전은 premium에서, 무료 버전은 master에서 작업하고 있고 premium에서 작업한 내용은 master에 적용되지 않았습니다.

🌱 브랜치 다뤄보기

지금까지 생성한 브랜치를 조회해보겠습니다.

git branch

master 브랜치 옆 별표(*)가 보이시나요? 이는 현재 위치한 브랜치를 나타내는 표시입니다. 즉, 우리는 현재 master 브랜치에 있다는 뜻이죠.

이번에는 브랜치를 새로 하나 만들고 삭제해보겠습니다.

git branch test

test라는 브랜치가 생겼습니다. 삭제를 하려면 -d 옵션을 주면 됩니다.

git branch -d test

test 브랜치가 삭제되었습니다. d는 delete의 줄임말입니다.

마지막으로 꿀팁 하나를 드리겠습니다. 앞서 브랜치를 생성하고 가장 먼저 해야할 일이 해당 브랜치로 이동하는 것이라고 했는데요. 브랜치 생성 시에 바로 브랜치로 이동할 수 있는 방법이 있습니다.

git checkout -b test

이렇게 하면 test 브랜치 생성과 동시에 test 브랜치로 이동하는 것을 확인할 수 있습니다. 브랜치를 생성하는 branch 커맨드 대신 다른 브랜치로 이동하는 checkout 커맨드를 적어주고 b 옵션을 주면 생성과 동시에 이동합니다.

브랜치 목록을 확인하면 test에 별표가 붙어있는 것이 보입니다. 즉, test 브랜치가 생성되고 바로 test 브랜치로 이동한 것이죠.

복습할 겸, master 브랜치로 돌아가 test 브랜치 삭제 후에 브랜치 목록을 조회해보세요.

🌱 브랜치 merge하기

현재 브랜치는 유료 버전을 위한 premium 브랜치와 무료 버전을 위한 master 브랜치로 나누어져 있습니다. 앞으로는 필요에 따라 checkout을 통해 두 브랜치로 이동하겠습니다.

master 브랜치에서 작업을 이어가 봅시다. Sublime Text에서 calculator.py 파일을 열어주세요. 그리고 divide 함수를 추가해주겠습니다.

def divide(x, y):
    return x/y

저장 후, 터미널로 이동해주세요. git add를 하고 커밋까지 하겠습니다. 커밋 메시지는 Add divide function으로 적어주면 됩니다.

git add .
git commit -m "Add divide function"

커밋이 완료되었습니다.

그런데 통상 유료 버전에는 무료 버전에 있는 기능을 모두 가지고 있는 경우가 많습니다. 이에 더해서 유료 사용자만을 위한 기능이 추가되는 거죠. 따라서, 유료 버전에도 방금 생성한 기능을 추가해줘야 합니다.

물론 premium branch로 가서 직접 divide 함수를 추가하고 커밋을 해도 되지만 특정 브랜치에서 한 커밋을 그대로 다른 브랜치에 반영하는 Git의 기능을 사용해보겠습니다.

premium 브랜치로 이동해봅시다.

git checkout premium

지금 상태에서 calculator.py의 내용을 출력해보면 multiply 함수와 divide 함수가 없습니다.

cat calculator.py

그 이유는 divide 함수를 추가한 것이 master 브랜치에서 진행한 작업이기 때문입니다. 이를 premium 브랜치에도 똑같이 반영하려면 방금 말한 작업을 하면 되는데요. 그 작업을 바로 'branch merge'라고 합니다. merge는 '병합하다, 합치다'라는 뜻을 가지고 있습니다.

merge를 해보겠습니다. merge 뒤에는 합쳐줄 브랜치 명을 입력하면 됩니다.

git merge master

위 커맨드를 해석하면 현재 위치인 premium 브랜치에 master 브랜치를 합치겠다는 뜻입니다.

위 커맨드를 입력하면 이런 창이 뜨는데요. 우리는 이와 유사한 창을 한 번 본 적이 있습니다. 바로 커밋 메시지를 남기는 방법 중 텍스트 에디터에 남기는 방법을 사용할 때 봤었죠.

merge를 하면 merge 커밋이라는 새로운 커밋이 생깁니다. 그래서 이렇게 커밋 메시지를 적는 창이 뜬 거죠. 위에 노란색 글씨가 커밋 메시지입니다. 지금은 이 메시지를 그대로 사용해보겠습니다.

저장은 :wq를 하고 엔터를 치면 됩니다.

그럼 위와 같이 merge가 되었다는 Merge made라는 문구가 뜹니다. 그런 다음 다시 한번 calculator.py를 출력하면,

master 브랜치와 마찬가지로 multiply 함수와 divide 함수가 보입니다.

🌱 merge conflict

merge를 할 때, 오류가 발생하는 경우가 있습니다. 어떤 경우인지 직접 코딩을 하면서 알아보도록 하겠습니다.

지금 우리는 premium 브랜치에 있습니다. 여기서 calculator.py 파일을 고치려고 합니다. Sublime Text로 이동해서 calculator.py 파일을 연 후, divide 함수 이름 뒤에 premium이라고 추가해줍니다.

그런 다음, 저장을 하고 터미널로 이동해서 git add와 커밋까지 완료해줍니다.

git add .
git commit -m "Change divide function as premium"

다음으로 master 브랜치로 이동하겠습니다.

git checkout master

그 다음, 다시 Sublime Text로 돌아와 이번에는 divide 함수 이름 뒤에 free를 적어주겠습니다.

이제 위와 동일하게 git add 후, 커밋까지 완료해줍니다.

여기까지 문제없이 잘 진행됩니다.

지금 우리는 똑같은 divide 함수를 premium 브랜치와 master 브랜치에서 서로 다른 이름으로 변경했습니다.

다시 premium branch로 이동합니다.

git checkout premium

지금 이 상태에서 master 브랜치를 merge하면 어떻게 될까요?

git merge master

실행하니 처음 보는 메시지가 출력됩니다. CONFLICT라는 문구가 보이시나요? 그 뒤로는 calculator.py 파일에서 merge conflict가 발생했다는 메시지가 보입니다. 다시 말해, merge를 하다가 충돌이 발생했다는 겁니다.

무슨 일이 일어났는지 확인하기 위해 Sublime Text로 돌아가보겠습니다.

파일을 열어보니 작성하지 않은 내용들이 입력되어 있습니다. 바로 이 부분이 conflict가 발생한 부분인데요. 자세히 살펴 보면, HEAD라는 부분이 premium 브랜치에서 수정한 부분이고 ==== 아래 부분이 master 브랜치에서 수정한 부분입니다. 가운데 선을 기준으로 각 브랜치에서 수정된 내용이 출력되었습니다.

현재 상황을 정리하면, 같은 divide 함수를 두고 premium 브랜치와 master 브랜치에서 함수명을 각각 다르게 수정했습니다. 이런 상황에서 두 브랜치를 merge하려 하니 Git은 두 함수명 중 어떤 것을 반영해야 할지 결정하지 못하게 된 것입니다.

이와 같은 상황을 conflict라고 합니다. Git은 conflict가 발생하면 사용자에게 이런 식으로 알려줍니다.

그럼 이제부터 conflict를 해결하는 방법을 알아봅시다. 현재는 premium 브랜치에서 master 브랜치를 merge 하려는 상황입니다. 여기서 선택을 해야 하는데요. 앞으로 premium 브랜치에서 divide 함수의 이름을 무엇으로 정할지를 말입니다. divide_premium으로 할지, 아니면 완전히 새로운 이름으로 정하는 것도 가능합니다.

오류가 난 divide 함수의 내용을 모두 지워줍니다. 그런 다음 divide_new라는 이름으로 함수를 다시 작성해주겠습니다.

def divide_new(x, y):
    return x/y

그 다음, 위와 같이 git add를 하고 커밋까지 완료합니다. 이번에는 커밋 메시지를 직접 입력해보겠습니다.

git commit

그럼 이와 같이 커밋 메시지를 입력할 수 있는 텍스트 에디터가 뜹니다. merge 커밋 때와 마찬가지로 노란 글씨로 커밋 메시지가 적혀 있는데요. conflict를 해결하고 커밋을 하면 이런 커밋 메시지가 자동으로 설정됩니다.

지금은 이 메시지를 그대로 사용하겠습니다. :wq를 통해 저장하고 종료해줍시다.

merge가 잘 되었는지 커밋 히스토리를 통해 확인해보겠습니다.

git history

HEAD를 보면 방금 작성했던 커밋 메시지가 보입니다.

사실 merge를 하다보면 conflict가 발생하는 경우가 많습니다. 그럴 때마다 당황하시는 분들이 많은데요. 그럴 필요가 전혀 없습니다. 다음 절차를 기억하면 됩니다.

  1. conflict가 발생한 파일 열기
  2. merge의 결과가 되었으면 하는 모습대로 코드 수정하기
  3. 커밋하기

❗ merge 자체를 취소하기

코드를 수정하지 않고 conflict를 해결할 수도 있는데요. merge 자체를 취소하면 됩니다.

merge를 하다가 conflict가 생겨 코드에 위와 같은 부분이 추가되었습니다. 이때, merge를 취소해보겠습니다.

git merge --abort

abort는 우리말로 '버리다, 취소하다'라는 뜻입니다.

위 커맨드를 실행하면 conflict 표시가 말끔히 사라지고 premium 브랜치에 있던 calculator.py의 원래 모습 그대로 돌아갑니다. 즉, merge를 시도하기 전 모습으로 돌아간 것이죠.

물론 merge를 꼭 해야 하는 상황이라면 취소할 필요없이 코드 수정 후 merge를 계속 진행해야 합니다.

그러나 conflict가 발생한 파일들이 너무 많아서 conflict를 최소화 할 수 있는 방식으로 파일들을 다시 수정하고 커밋한 다음에 merge를 하고 싶다거나, 좀 더 나중에 merge를 하고 싶을 때에는 merge 자체를 취소하면 됩니다.

❗ 여러 파일에서 conflict가 났을 때

우리는 하나의 파일에서 conflict가 났을 때 대처하는 방법에 대해 알아봤습니다. 그런데 실무에서는 파일 여러 개를 수정하는 경우가 많다보니 merge를 할 때에도 conflict가 파일 여러 개에서 발생하기도 합니다.

이런 상황에서도 해결 방법은 파일이 하나일 때와 동일합니다.

위와 같이, 여러 파일을 작업했을 때에는 여러 conflict가 발생합니다. 상황에 대해 설명하자면, 어떤 상품에 대한 정보를 담는 price와 after_service, size 세 가지 파일을 master 브랜치와 premium 브랜치에서 각각 다른 모습으로 수정했습니다. 커밋까지 완료 후, merge를 진행하려 하니 conflict가 발생한 것이죠.

꼭 이런 출력 결과가 아니더라도 git status 커맨드를 사용하면 현재 conflict가 발생한 파일들의 목록을 확인할 수 있습니다.

앞서 해결 방법은 파일이 하나일 때와 동일하다고 했는데요. conflict가 발생했으니 각각의 파일들에 HEAD==== 등의 표시가 등장했을 겁니다. 그럼 아까 했던 것과 마찬가지로 이 내용들을 모두 삭제한 후, 원하는 모습대로 내용을 수정해 줍니다. 그 다음, 각각의 파일을 커밋해주면 되는 거죠.

price 파일의 conflict를 해결하고 커밋을 완료한 후, git status를 확인하면,


위와 같이 price 파일은 성공적으로 커밋이 완료된 것을 확인할 수 있습니다. 반면, 수정을 거치지 않은 나머지 두 파일들은 Unmerged라는 문구가 뜹니다. 이 두 파일들도 price와 같이 수정을 거치면 모든 파일들이 성공적으로 커밋을 완료했다는 문구가 뜹니다.

정리하자면, 여러 개의 파일에서 conflict가 발생했을 때에도 파일 하나씩 conflict를 해결하고(파일을 원하는 모습대로 수정하고) git add 커맨드로 하나씩 staging area에 올리거나, 모든 파일들의 conlict를 해결하고 git add .을 통해 한꺼번에 staging area에 올린 후 커밋을 진행하면 됩니다.


이번 시간에는 Git의 또 다른 중요 기능 브랜치에 대해서 알아봤습니다. 하나의 파일로부터 여러 버전을 나눈다는 것은 활용 가치가 매우 높아 보이네요. 브랜치에 익숙해져서 실제 개발을 할 때 유용하게 사용할 수 있길 바랍니다.

다음 시간에는 브랜치에 관한 또 다른 내용들을 함께 알아보겠습니다.

* 이 자료는 CODEIT의 'Git으로 배우는 버전 관리' 강의를 기반으로 작성되었습니다.
profile
There's Only One Thing To Do: Learn All We Can

0개의 댓글