Git에서는 브랜치를 아주 자유롭게 만들 수 있어 작업을 분할하기 좋지만, 브랜치를 효과적으로 관리하지 못하면 의미가 없어지게 됩니다. 따라서 프로젝트의 참여자 전체가 브랜치를 다루는 방식을 통일하는 것이 좋습니다. 새로운 브랜치의 생성 조건, 브랜치 네이밍, 통합 조건 등등의 규칙들입니다. 여기서 설명하려는 브랜칭 기법들은 일반적으로 브랜치를 통합 브랜치(Integration Branch)토픽 브랜치(Topic Branch)로 나눕니다.

통합 브랜치(Integration Branch)

통합 브랜치란 언제든지 배포할 수 있는 버전을 만들 수 있어야 하는 브랜치 입니다. 그렇기 때문에 늘 안정적인 상태를 유지하는 것이 중요합니다. 만약 어떤 문제가 발견되어 그 문제(버그)를 수정하거나 새로운 기능을 추가할 때, 토픽 브랜치를 만듭니다. 처음에는 보통 통합 브랜치에서 토픽 브랜치를 만들어 냅니다.

일반적으로 저장소를 처음 만들었을 때에 생기는 master 브랜치를 통합 브랜치로 사용합니다.

토픽 브랜치(Topic Branch)

토픽 브랜치란, 기능 추가나 버그 수정과 같은 단위 작업을 위한 브랜치 입니다. feature_x, feature_y, hotfix_z와 같은 형태의 브랜치들입니다. 여러 개의 작업을 동시에 진행할 때에는, 그 수만큼 토픽 브랜치를 생성하는 방식입니다.

토픽 브랜치는 보통 통합 브랜치로부터 만들어 내며, 토픽 브랜치에서 특정 작업이 완료되면 다시 통합 브랜치에 병합하는 방식으로 진행됩니다.

Git-flow

Git-flow는 Vincent Driessen의 'A successful Git branching model'을 적용하여 코드를 관리하는 전략입니다. Vincent의 브랜칭 모델은 'feature - develop - release - hotfixes - master'의 형태로 브랜치를 나누는데, git-flow도 별반 다르지 않습니다.

git-flow의 주요 브랜치는 masterdevelop입니다. 이 브랜칭 전략에서는 새 버전을 배포하기 위해 master 브랜치에 병합합니다. master 브랜치로 커밋될 때 git hook 스크립트를 걸어서 자동으로 빌드하고 운영 서버로 배포하는 형식을 취합니다.

feature

다음 버전을 위해 개발하는 코드는 develop에서 관리합니다. 그러나 이 브랜치 하나로는 한계가 있기 때문에, 보조 브랜치들을 사용합니다. 기능 개발을 위해 feature 브랜치를 사용합니다. develop에서 시작하고, 병합도 develop을 향합니다. feature 브랜치는 그 기능을 다 완성할 때까지 유지하고 있다가 다 완성되면 develop 브랜치로 병합합니다.

release

release 브랜치는 실제 배포할 상태가 된 경우에 생성하는 브랜치입니다. develop에서 시작하고, 병합은 develop과 master에 합니다. 지금까지 개발한 기능을 묶어 develop 브랜치에서 release 브랜치를 따내고, develop 브랜치에서는 다음번 릴리즈를 위한 준비, release 브랜치에서는 버그픽스에 대한 부분만 커밋하게 되고 릴리즈가 준비되었다고 생각하면 master로 머지를 진행합니다. 이후 tag 명령을 이용하여 릴리즈 버전에 대해 명시합니다.

hotfix

production 과정에서 발생한 버그들은 전부 hotfix로 이동합니다. master에서 시작하고, 병합은 develop과 master에 합니다. 이미 배포한 운영버전에서 발생한 문제를 해결하기 위해 만드는 브랜치입니다. 운영 버전에 생긴 치명적인 버그는 즉시 해결해야 하기 때문에, 마스터 브랜치에 만들어둔 태그로부터 hotfix 브랜치를 생성합니다.

git-flow는 꽤 오래 전에 나온 전략인데, git-flow만의 단점(브랜치가 많아 복잡하고, 안 쓰는 브랜치가 있으며 몇몇 브랜치의 포지션은 애매함)을 극복하기 위해 github flowgitlab flow 전략이 나왔습니다.

Github-flow

Github-flow는 배포가 정기적으로 이루어지는 프로젝트를 위한 브랜치 기반 workflow입니다. 브랜치 전략이 단순하고, Pull request 위주로 각 브랜치들의 변경 사항을 머지하므로 코드 리뷰를 자연스럽게 수행할 수 있습니다. Git flow는 좋지만, Github에서 사용하기에는 복잡하다는 입장에서 만들어졌습니다.

브랜칭

브랜칭은 git의 핵심 개념이며, 전체 Github flow는 이를 기반으로 합니다. Github flow에서는 브랜치에 대해 딱 한가지 규칙만이 있는데, master 브랜치의 모든 항목은 항상 배포 가능한 상태여야 한다는 것입니다. 따라서, 기능 구현이나 수정 작업을 할 때 master에서 브랜치를 생성해야 합니다.

Github-flow에서는 브랜치 네이밍, 브랜치 생성, 삭제에 관한 규칙도 따로 없으며, master 브랜치에 대한 규칙 하나만 정확하면 됩니다.

커밋

브랜치가 생성되고 나면, 변경 사항을 만들어낼 것입니다. 파일을 추가, 편집, 삭제할 때마다 커밋을 추가하게 됩니다. 각 커밋에는 관련된 변경 메시지가 있으며, 이는 해당 변경이 이루어진 이유를 설명합니다. 각 커밋은 별도의 변경 단위로 간주되며, 따라서 특정 커밋으로 돌아가거나, 복구하는 데에 편한 환경을 만들어낼 수 있습니다.

Pull request

Pull request는 Github-flow의 가장 중요한 요소입니다. 브랜치 간의 병합을 위해 단순히 merge만을 사용하지 않고, 한 번의 리뷰를 거치도록 변경 사항을 '요청'하는 일입니다. 따라서 Pull request라는 개념은 특히 오픈 소스 프로젝트의 기여에 자주 사용됩니다. 개발 프로세스 중 언제라도 Pull request를 열 수 있고, 이는 해당 브랜치의 변경 사항에 대한 토론을 시작합니다. Github-flow에서 Pull request는 master 브랜치에 변경 사항을 병합하기 전에 코드를 리뷰하기 위한 용도로 자주 사용됩니다.

'Git 레거시 글' 카테고리의 다른 글

[Git] 다시 커밋하기  (0) 2018.05.27
[Git] 파일 상태 Lifecycle 관리하기  (0) 2018.05.26
[Git] 브랜치와 Merge  (0) 2018.05.24
[Git] Pull에서 충돌 해결하기  (1) 2018.05.23
[Git] 원격 저장소에서 Pull받기  (0) 2018.05.22

여러 개발자가 동시에 작업하다 보면, 동일한 소스코드 위에서 기능을 추가할 때도 있고, 버그를 수정할 때도 있습니다. 따라서 동일한 소스코드를 기반으로 작업을 하더라도 다양한 버전의 코드가 만들어질 수밖에 없습니다. 이럴 때, 각자 독립적인 작업 영역 안에서 작업할 수 있도록 해주는 것이 브랜치(branch)입니다. 각각의 브랜치는 다른 브랜치의 영향을 받지 않기 때문에 여러 작업을 동시에 진행할 수 있습니다. 브랜치는 분기라는 뜻이지만 동사로서 가지를 뻗다라는 뜻도 가지고 있고, 실제로 브랜치는 가지를 뻗는다는 느낌으로 생각하면 됩니다.

브랜치의 생성과 이동

Git에서는 항상 작업할 브랜치를 선택해야 합니다. 처음에는 master 브랜치가 선택되어 있습니다. 다른 브랜치로 이동하기 위해서는 checkout 명령을 사용하고, 존재하지 않는 브랜치라면 이동되지 않기 때문에 branch 명령으로 브랜치를 만들고 나서 checkout해 봅시다.

git branch [branch_name]

$ git branch feature_x

별다른 인자 없이 git branch만을 실행하면 브랜치 목록 전체를 확인할 수 있습니다. * 표시는 현재 선택된 브랜치를 뜻합니다.

$ git branch
 master
 * feature_x

브랜치를 삭제하려면 -d 옵션을 이용하면 됩니다.

$ git branch -d feature_x

git checkout [branch_name]

$ git checkout feature_x

checkout이 성공하면, 브랜치 안에 있는 마지막 커밋 내용이 작업 트리에 펼쳐집니다. 브랜치가 전환되었으므로 이 후에 실행한 커밋은 전환한 브랜치에 적용됩니다. Git의 브랜치에는 HEAD라는 특수한 포인터가 있습니다.

HEAD는 현재 작업하는 로컬 브랜치을 나타내는 이름입니다. 기본적으로는 master 브랜치의 선두 부분을 나타냅니다. HEAD를 이동하면, 사용하는 브랜치가 변경됩니다. 따라서 현재 masterfeature_x 브랜치가 존재하고, feature_x 브랜치로 이동했으므로 HEAD는 feature_x에 있습니다.

checkout에서 -b 옵션을 함께 붙여주면 브랜치 생성과 이동을 한번에 실행할 수 있습니다.

$ git checkout -b feature_y

Merge

git merge [branch_name]

다른 브랜치의 변경사항을 현재 브랜치에 병합하기 위해 사용합니다. 예를 들어, 현재 브랜치가 masterfeautre_x 브랜치의 변경사항을 병합하려면 아래의 명령을 실행합니다.

$ git merge feature_x

여기서도 conflict가 발생할 수 있으며, pull에서 conflict가 발생했던 경우와 동일하게 해결하고 add - commit - push하면 됩니다.

자신의 로컬 저장소에서 진행한 변경 이력을 원격 저장소에 push할 당시에, 로컬 저장소가 최신 버전이 아닌 경우(clone 이후 다른 사람이 remote에 push를 진행했을 경우) 자신의 push 요청이 거절됩니다. 이런 경우 병합(merge) 작업을 진행하여 remote에 반영된 다른 사람의 변경 이력을 로컬 저장소에 갱신해야 합니다. 원격 저장소의 변경 사항을 무시하고 자신의 변경 이력을 덮어쓸 수도 있습니다. 아래는 강제 push의 몇가지 예입니다.

$ git push -f
$ git push --force
$ git push origin +<branch_name>

그러나 강제 push를 할 일을 만드는 것은 정말 좋지 않은 일입니다. remote의 변경 이력을 로컬로 merge하는 것이 가장 좋습니다. 그냥 단순히 pull만 하면 됩니다.

$ git pull origin master

문제될 상황이 없다면 git이 알아서 변경 사항을 통합해 줍니다. 여기서 문제 상황은 충돌(conflict)인데, 예를 들어 로컬 저장소에서 README.md라는 파일을 변경했고, 가장 최근 로컬 저장소의 pull 이후 remote의 변경 이력에 README.md의 수정이 포함되어 있다면 충돌이 발생합니다.

충돌 해결하기

병합 기능은 경우에 따라 자동으로 병합할 수 없는 경우가 있고, 그 경우가 바로 충돌이며, 로컬 저장소의 변경 대상과 remote의 변경 대상이 같을 때 충돌이 발생한다고 했습니다. 두 변경 내용 중 어떤 것을 적용할 것인지 판단할 수 없기 때문입니다. 이 경우 git은 적용할 변경 내용의 판단을 개발자에게 맡깁니다. 따라서 충돌은 수동으로 수정해 주어야 합니다. 아래는 충돌이 난 파일의 예입니다.

<<<<<<< HEAD
Hello
=======
Hello!
>>>>>>> aab6d380aaf237a7c0aae28e00ea4607c8a7eec9

'======='로 구분된 위쪽 부분이 로컬 저장소, 아래쪽 부분이 remote의 변경 내용입니다. 둘 중 어떤 변경 이력을 적용할 지 선택하고, 모든 충돌 부분을 수정한 이후 커밋을 수행하면 됩니다.

'Git 레거시 글' 카테고리의 다른 글

[Git] 브랜칭 기법  (0) 2018.05.25
[Git] 브랜치와 Merge  (0) 2018.05.24
[Git] 원격 저장소에서 Pull받기  (0) 2018.05.22
[Git] 원격 저장소에 Push하기  (3) 2018.05.21
[Git] 원격 저장소 만들기  (0) 2018.05.20

+ Recent posts