GitHub에서 Gitflow Workflow를 이용하여 협업하는 방법

이 POST와 관련된 PDF 자료는 https://github.com/gmlwjd9405/git-collaboration에서 다운받을 수 있습니다.
(You can download the PDF file related to this POST from the following link.)

Goal

  • Gitflow Workflow의 개념을 파악한다.
  • Gitflow Workflow로 협업하는 방법을 익힌다.

Gitflow Workflow

1. 중앙 원격 저장소, 자신의 원격 저장소, 로컬 저장소의 개념

2. 프로젝트 참여자는 git clone 명령으로 로컬 저장소를 만든다.

git clone 명령으로 중앙 원격 저장소(remote repository)를 복제하여 자신의 로컬 저장소(local repository)를 만들 수 있다. 프로젝트 참여자는 이 로컬 저장소에서 작업을 수행한다.

// 터미널에서 자신의 원하는 디렉터리 이동한 후 아래의 명령어를 입력
/**
해당 디렉터리
  --하위--> remote repository와 동일한 이름의 디렉터리 생성
**/
$ git clone [중앙 remote repository URL]
//해당 디렉터리를 빈 Git 저장소로 만드는 작업
$ git init
// 현재 작업 중인 Git 저장소에 팀의 중앙 원격 저장소를 추가한다. 이름을 origin으로 짓고 긴 서버 주소(URL) 대신 사용한다.
$ git remote add origin [중앙 remote repository URL]
// 중앙 원격 저장소(origin)의 master 브랜치 데이터를 로컬에 가져오기만 하는 작업
$ git fetch origin master

fetch와 pull의 차이

3. 가장 먼저 할 일은 Develop Branch를 만드는 것이다.

‘master’ 브랜치를 기준으로 develop 브랜치를 만든다.

방법 [1]: GUI 도구를 이용한 생성(이 방법을 추천한다!)

방법 [2]: 팀 구성원 중 한 명이 자신의 로컬 저장소에 빈 develop 브랜치를 만들고 중앙 저장소로 푸시

$ git branch develop
$ git push -u origin develop
  1. GitHub 페이지에서 자신이 push한 ‘develop’ branch를 병합해달라는 pull request를 날린다.
  2. 프로젝트 관리자는 해당 pull request를 merge하여 새로운 ‘develop’ branch를 중앙 원격 저장소에 생성한다.
  3. 방법 [1]과 같은 방법으로 새로 생성한 ‘develop’ branch를 default branch로 설정한다.

4. 팀 구성원 모두가 Gitflow Workflow를 적용할 준비를 한다.

이제 팀 구성원들은 중앙 저장소를 복제(처음에 clone 했으면 넘어감)하고, 중앙 저장소와 연결된 개발 브랜치를 만들어야 한다.

$ git checkout -b develop origin/develop

이제 팀 구성원 모두가 이 워크플로우를 적용하기 위한 준비가 되었다고 가정하자.

5. 설명을 위해 현재 로컬에서 작업 중인 branch 위치를 표시한다.

중앙 원격 저장소에는 master, develop branch가 있고, 자신의 로컬 저장소에는 master, develop branch와 로그인 기능을 구현할 feature/login branch(아래에서 설명)가 있다고 가정한다.
또한 현재는 master branch에서 작업 중이라고 가정하고 아래와 같이 작업 중인 위치를 표시한다. (Gitflow Workflow에서는 대부분의 작업이 develop branch에서 이루어진다.)

6. 새로운 기능 개발을 위해 격리된 branch를 만든다.

로컬 저장소에서 branch를 따고, 코드를 수정하고, 변경 내용을 커밋한다.
이때, ‘master’ branch에서 기능 개발을 위한 브랜치를 따는 것이 아니라, ‘develop’ branch에서 따야한다.

$ git checkout -b [branch name] develop

# 위의 명령어는 아래의 두 명령어를 합한 것
$ git branch [branch name] develop
$ git checkout [branch name]

7. 로컬 저장소의 새로운 기능 브랜치를 중앙 원격 저장소(remote repository)에 푸시한다.

$ git commit -a -m "Write commit message"

# 위의 명령어는 아래의 두 명령어를 합한 것
$ git add . # 변경된 모든 파일을 스테이징 영역에 추가
$ git add [some-file] # 스테이징 영역에 some-file 추가
$ git commit -m "Write commit message" # local 작업폴더에 history 하나를 쌓는 것

방법 [1]: 팀이 “풀 리퀘스트(pull request)”를 이용하는 경우,

방법 [2]: 팀이 “풀 리퀘스트(pull request)”를 이용하지 않는 경우,

# -u 옵션: 새로운 기능 브랜치와 동일한 이름으로 중앙 원격 저장소의 브랜치로 추가한다.

// 로컬의 기능 브랜치를 중앙 원격 저장소 (origin)에 올린다.
$ git push -u origin feature/login branch

// -u 옵션으로 한 번 연결한 후에는 옵션 없이 아래의 명령만으로 기능 브랜치를 올릴 수 있다.
$ git push -origin feature/login branch

8. 중앙 원격 저장소와 자신의 로컬 저장소를 동기화하기 위해 로컬 저장소의 branch를 develop branch로 이동한다.

// 로컬 저장소의 branch를 develop branch로 이동
$ git checkout develop

9. 중앙 원격 저장소의 코드 베이스에 새로운 커밋이 있다면 다음과 같이 가져온다.

중앙 원격 저장소(origin)의 메인 코드 베이스(‘develop’ branch)가 변경되었으므로, 프로젝트 참여하는 모든 개발자가 자신의 로컬 저장소를 동기화해서 최신 상태로 만들어야 한다.

$ git pull origin develop

10. 새로운 기능을 추가하기 위해서 그 작업에 대한 branch를 생성하여 작업한다.

중앙 원격 저장소와 동기화된 로컬 저장소의 ‘develop’ branch에서 새로운 작업에 대한 branch를 생성하여 다른 작업을 시작한다.


Feature Branch Workflow라면 develop 브랜치에 개발한 기능을 병합하는 것으로 모든 과정이 끝날테지만, Gitflow Workflow는 아직 할 일이 더 남아 있다.


11. 배포하기

만약 ‘develop’ 브랜치에서 버전 1.2에 대한 기능이 모두 구현이 되었으면 배포를 위한 전용 브랜치를 사용하여 배포 과정을 캡슐화한다. 이렇게 함으로써 한 팀이 해당 배포를 준비하는 동안 다른 팀은 다음 배포를 위한 기능 개발을 계속할 수 있다.
버전 번호를 부여한 새로운 ‘release’ branch를 ‘develop’ branch로부터 생성한다.

// 'develop' 브랜치로부터 release 브랜치(release-1.2)를 생성
$ git checkout -b release-1.2 develop

  1. ‘master’ 브랜치에 병합한다. (이때, 병합한 커밋에 Release 버전 태그를 부여!)
  2. 배포를 준비하는 동안 release 브랜치가 변경되었을 수 있으므로 배포 완료 후 ‘develop’ 브랜치에도 병합한다.
  3. 작업했던 release 브랜치는 삭제한다. 이때, 다음 번 배포(Release)를 위한 개발 작업은 ‘develop’ 브랜치에서 계속 진행해 나간다.

방법 [1]: 팀이 “풀 리퀘스트(pull request)”를 이용하지 않는 경우,

/* release 브랜치에서 배포 가능한 상태가 되면 */
// 'master' 브랜치로 이동한다.
$ git checkout master
// 'master' 브랜치에 release-1.2 브랜치 내용을 병합(merge)한다.
# --no-ff 옵션: 위의 추가 설명 참고
$ git merge --no-ff release-1.2
// 병합한 커밋에 Release 버전 태그를 부여한다.
$ git tag -a 1.2
// 'master' 브랜치를 중앙 원격 저장소에 올린다.
$ git push origin master

/* 'release' 브랜치의 변경 사항을 'develop' 브랜치에도 적용 */
// 'develop' 브랜치로 이동한다.
$ git checkout develop
// 'develop' 브랜치에 release-1.2 브랜치 내용을 병합(merge)한다.
$ git merge --no-ff release-1.2
// 'develop' 브랜치를 중앙 원격 저장소에 올린다.
$ git push origin develop

// -d 옵션: release-1.2에 해당하는 브랜치를 삭제한다.
$ git branch -d release-1.2

방법 [2]: 팀이 “풀 리퀘스트(pull request)”를 이용하는 경우,

팀이 풀 리퀘스트를 통한 코드 리뷰하는 방식을 사용한다면 release 브랜치를 그대로 중앙 원격 저장소에 올린 후 다른 팀원들의 확인을 거쳐 ‘master’와 ‘develop’ branch에 병합한다.

12. 버그 수정하기

배포한 버전에 긴급하게 수정을 해야 할 필요가 있을 경우, ‘master’ 브랜치에서 직접 브랜치(‘hotfix’ 브랜치)를 만들어 필요한 부분만을 수정한 후 다시 ‘master’브랜치에 병합하여 이를 배포해야 한다.
‘develop’ 브랜치에서 문제가 되는 부분을 수정하여 배포 가능한 버전을 만들기에는 시간도 많이 소요되고 안정성을 보장하기도 어렵기 때문이다.

// release 브랜치(hotfix-1.2.1)를 'master' 브랜치(유일!)에서 분기
$ git checkout -b hotfix-1.2.1 master

/* ~ 문제가 되는 부분만을 빠르게 수정 ~ */

/* 필요한 부분을 수정한 후 */
// 'master' 브랜치로 이동한다.
$ git checkout master
// 'master' 브랜치에 hotfix-1.2.1 브랜치 내용을 병합(merge)한다.
$ git merge --no-ff hotfix-1.2.1
// 병합한 커밋에 새로운 버전 이름으로 태그를 부여한다.
$ git tag -a 1.2.1
// 'master' 브랜치를 중앙 원격 저장소에 올린다.
$ git push origin master

/* 'hotfix' 브랜치의 변경 사항을 'develop' 브랜치에도 적용 */
// 'develop' 브랜치로 이동한다.
$ git checkout develop
// 'develop' 브랜치에 hotfix-1.2.1 브랜치 내용을 병합(merge)한다.
$ git merge --no-ff hotfix-1.2.1
// 'develop' 브랜치를 중앙 원격 저장소에 올린다.
$ git push origin develop

// -d 옵션: hotfix-1.2.1에 해당하는 브랜치를 삭제한다.
$ git branch -d hotfix-1.2.1
  1. 배포한 버전에 긴급하게 수정을 해야 할 필요가 있을 경우,
    • ‘master’ 브랜치에서 hotfix 브랜치를 분기한다. (‘hotfix’ 브랜치만 master에서 바로 딸 수 있다.)
  2. 문제가 되는 부분만을 빠르게 수정한다.
  3. 다시 ‘master’ 브랜치에 병합(merge)하여 이를 안정적으로 다시 배포한다.
  4. 새로운 버전 이름으로 태그를 매긴다.
  5. hotfix 브랜치에서의 변경 사항은 ‘develop’ 브랜치에도 병합(merge)한다.
  6. 작업했던 hotfix 브랜치는 삭제한다.

관련된 Post

References