목적 : git flow 전략을 github과 sourcetree를 이용하여 이해하기.
여러 사람들이 협업하여 project를 진행하려면 형상관리가 필수입니다. 각 그룹이나 회사에서는 저마다 맞는 방식의 전략을 가지고 형상관리를 하고 있는데, 그 중에서 보편화 되어있는 git flow 전략에 대해 알아보고 따라해보도록 하겠습니다.
git flow 는 거대한 프로젝트에서 여러 개발자가 동시에 각각의 서비스를 개발하고 다시 merge 작업을 하며 실제 운영에 release를 하기 전 다양한 테스트를 할 수 있게 해주기 용이한 전략이라고 합니다.

너무나도 유명한 git-flow branch 전략 그래프.
- master : product로 배포할 브랜치(혹은 배포된 브랜치)
- develop : 개발버전 브랜치
- feature : 각 기능별, 서비스별 개발중인 브랜치
- release : master로 올리기전 준비하는 브랜치
- hotfixes : master에서 나온 버그를 빠르게 수정하는 브랜치
1. 준비사항
repository는 github에서 진행하며, 형상관리 프로그램은 sourcetree를 사용하겠습니다. 혹시 이미 준비가 완료된 상황이면 이 챕터1은 건너 뛰셔도 됩니다.
1) sourceTree 다운로드 및 github 가입
2) github accessToken 생성
21년 하반기부터 Github 사용시에 ID/PASSWORD 기반의 Basic Authentication 을 없애고, ID/Personal Access Token 기반의 Token Authentication로 바뀌었다고 한다.
그래서 꼭 access token 을 주기적으로 발급받아 사용해주어야 한다.
- 우측상단 프로필 항목에서 Settings 탭 선택

- 왼쪽 메뉴 최하단 Developer settings 선택

- 다시 왼쪽 메뉴 Personal access tokens > 우측 Generate new token 선택

- 어떤 토큰인지 간단하게 note 부분에 적어주고 만료일은 만료되면 token 다시 발급받으면 되니 그냥 30days로 지정합니다. 하단에 권한 범위는 workflow정도만 지정해도 무방합니다. 맨 아래에 generate 버튼을 누릅니다.

- 정상적으로 발급이 되면 token 정보가 나오는데 이제 이 정보를 복사해서 패스워드 대신에 사용해줍니다. (메모장 같은곳에 복사 붙여넣기 ㄱㄱ)

3) sourceTree 계정 연결
- sourceTree를 실행한뒤 메뉴에서 설정 > 계정 탭 선택 > 추가 버튼

- 호스트 github 선택. 인증방식은
08년도 베이식. 이 아닌 베이직으로 선택 후, 이름은 github ID. 암호는 아까 복사해두었던 access token 붙여넣기. 후 저장

- 잘 저장된 거 확인

2. github repository 생성
1) github으로 돌아가 repositories 탭에서 새로운 레포지터리를 만들어줍니다.

- 적당하게 이름을 지어주고 무료 사용자이기 때문에 public 으로 생성이 됩니다.. 아래 repository에 미리 추가할 file을 선택하라고 나오는데 선택 하지 않고 갑니다.

2) 레포지터리 생성 확인
아래 화면처럼 나오면 잘 생성된 겁니다. 이제 진짜 git-flow 전략을 따라해보도록 하겠습니다.
우선 저 https git 주소를 복사합니다.

3) 소스트리 원격 레포지터리 복제
- 이제 다시 sourceTree를 열어 원격 레포지터리 새로만들기 > url에서 복제를 선택합니다.

- git주소를 붙여넣고 경로를 적당한데다 잘 만들어줍니다

- 레포지터리 클로닝 된거 확인하고

3. Branch들 생성하기
1) master 브랜치
아까 github에서 레포지터리를 생성할 때 'add a README file' 항목을 이용해서 만들어도 되지만!! 연습삼아 직접 README.md 파일 생성해서 한번 만들어보겠습니다.
- 터미널을 열어 저장소 경로로 이동(ls 명령어로 목록 검색 ,cd 폴더명으로 이동)
- vi 편집기 명령어를 이용하여 README.md 파일 생성(이 md는 markdown 의 약어 확장자 파일입니다)

- vi 편집기 사용방법은 간단하게 i(Insert)를 누르면 편집이 시작되며, 작성할 내용을 넣고 Esc를 누르고 명령어로 :wq 입력 후 엔터를 치면 저장이 됩니다. (vi 명령어로 구글링하면 더 자세한 내용 확인이 가능합니다.)

- 터미널에서도 git 명령어를 사용할 수 있지만 저는 sourcetree를 이용하여 형상관리를 해보도록 하겠습니다. sourcetree에서 아까 복제된 저장소를 보겠습니다. 방금 만든 파일이 커밋을 기다리고 있습니다.

- 스테이지에 올라가지 않은 파일 목록을 눌러 커밋과 푸시를 해보도록 하겠습니다.

- 변경사항 내용을 적고 커밋을 합니다

- 커밋을 하면 로컬 브랜치가 생성됩니다.

- 이 main브랜치명은 master로 바꿔줍니다.(원격 브랜치는 기본명칭이 master로 되어 있으니 local 브랜치명만 바꿔줍니다.)

- 이제 원격브랜치에 push를 해줍니다.

- 첫 파일을 올렸습니다.

- github에도 올라왔네요.

- 푸시된 그래프 항목 우클릭하여 '태그' 선택해서 달아줍시다.

- github에서도 1 branch 1 tag가 되었네요

2) develop 브랜치
develop 브랜치 생성
- sourceTree에서 브랜치 버튼을 눌러 새브랜치를 생성합니다. 브랜치명은 develop (dev라고도 많이들 작업하는 것 같습니다.) 그리고 브랜치 생성 버튼을 누릅니다.

- 그리하면 왼쪽 로컬브랜치 목록에 develop 항목이 생성되었을 것입니다.

- 바로 푸시를 눌러 원격 레포지터리에도 브랜치를 만들어줍니다. (푸시 체크)

- 이제 develop 브랜치가 생성되었으며, 개발할 때 이 develop 브랜치에서 내려받아 작업하고 최종적으로는 master로 merge 하여 product를 만들도록 작업해주면 됩니다.

develop 브랜치에 바로바로 push
- 간단한 개발사항은 바로바로 develop에서 push를 해줘도 되지만 오래걸리는 기능개발사항은 별도 feature branch를 생성하여 작업해줘야 합니다. 우선 develop에도 몇번 push를 해보겠습니다.
- 작업할 파일을 만들어줍니다. 똑같이 vi 편집기를 이용하여 아무 내용의 파일이나 만듭니다.(다른 편집기가 있으면 그걸로 작업 ㄱㄱ)
- 저는 fileOne이라는 파일을 만들었습니다. sourceTree에서 커밋을 기다리고 있네요.

- commit 후 push까지 해줍니다.

- 또 파일을 수정도 한번 하고 commit -> push 해봅니다.

3) feature 브랜치
간단한 개발사항은 develop에서 작업을 했지만, 개발인원이 많아지고 소스의 충돌을 막기 위해 feature 브랜치를 별도로 생성해서 작업을 해줘야 합니다.
현재 있는 develop 브랜치에서 또 feature 브랜치 가지를 내려보도록 하겠습니다.
feature 브랜치 생성 (feat. 개발자 A)
- 이제 나는 새로운 개발자A라는 생각으로 진행해보겠습니다.
- master 에서 develop 가지치기 했을 때랑 동일하게 만들어주면 됩니다.
- 우선 github에서 원격레포지터리 클론 작업을 먼저 합니다. git 저장소 주소를 복사하고

- SourceTree에서 원격저장소 복제를 하고

- 저장소 복제시 나는 이제 새로운 개발자 A이므로 새로운 폴더에 작업합니다. 고급옵션에 체크아웃할 브랜치는 develop으로 선택합니다. (내려받은 후에도 체크아웃할 브랜치 변경은 가능합니다.)

- 저장소가 잘 만들어졌습니다.

- feature 브랜치를 만들어줍니다. feature 명칭은 기능명칭을 적어주는게 좋습니다.
- 이 개발자 A는 fireball 기능을 담당하는 개발자라고 합니다.

- feature 브랜치 생성후 push도 합니다.

- 자 feature 브랜치가 만들어졌으면 개발자 A는 fireball을 만듭니다. (새로운 파일 생성)
- 파일을 만들고 feature 브랜치에 commit push 합니다.

feature 브랜치 생성 (feat. 개발자 B)
- 자 이번에는 또다른 개발자 B가 있다고 생각합니다.
- 개발자 A랑 동시에 다른 업무가 B한테도 주어졌고, 같이 서로 다른 기능을 개발해야 합니다.
- 개발자 B도 똑같이 develop브랜치에서 새로운 feature 브랜치를 생성해줍니다.

- 이 개발자 B는 처음에 master 버전으로 git을 시작했습니다.

- 원격저장소에서 develop 브랜치를 선택하여 체크아웃하고

- 브랜치가 develop 으로 잘 체크아웃되어있는지 확인하고 새브랜치(feature 브랜치)를 생성해줍니다.
- 이 개발자 B는 sword 기능을 만드는 개발자입니다.

- feature 브랜치 생성했으면 또 파일 하나 만들어서 작업해주고,

- feature/sword 에 커밋 푸시 해줍니다.(개발자 A도 열심히 작업중인 내용이 그래프에 보이네요.)

- 저 하단에 즉시 푸시 기능 체크 하면 편합니다. (조심해서 사용하시길)

develop 브랜치 bug fix
- 자 이와중에 저 feature 에서 작업중인 기능들과는 별개로 간단한 bug fix 작업 같은게 있으면 또 feature를 딸 필요 없이 바로 develop에서 작업해줍니다.
- 기존 develop 을 관리하던 원 개발자가 간단한 개발 후에 git에 올린다고 가정해봅시다.
- sourceTree에서 아까 제일 처음에 만들었던 저장소와 폴더 경로에 있는 파일 수정작업을 해줍니다.

- 위 그래프를 보면 master -> develop -> feature 개발중 -> develop에서 간단한 개발후 push 형태입니다. 이 상태 진행 중과 같은 상태입니다.

- 토대가 되는 브랜치는 develop이며, 기능 개발은 별도의 feature를 따서 진행합니다.
4) hotfixes 브랜치
이번에는 실제 운영중인 production에서 문제가 발생했다고 가정합니다. (테스트에서는 발견되지 않은 그런 문제들...)
hotfixes 브랜치 생성
- develop에서의 간단한 bug fix는 바로 develop 브랜치에서 push를 하고, master는 별도로 hotfixes 브랜치를 생성합니다.
- 브랜치 생성법은 이전과 동일합니다.
- clone repository
- master checkout
- hotfixes new branch
- hotfixes remote repository push
- 이번에는 기존에 가지고 있던 프로젝트에서 hot fix 작업을 해보겠습니다.
- 기존 develop 브랜치를 가지고 있는 sourcetree 레포지터리와 파인더로 해당 경로를 열어보겠습니다.

- develop에서는 아까 모든 변경사항을 push 했기에 따로 변경사항이 없다고 나옵니다. 이런 clean 한 상태에서 브랜치를 master로 체크아웃하게 되면, 가지고 있는 프로젝트 내용도 master branch의 내용과 동일해지며, master branch를 바라보게 됩니다.

- 현재 브랜치가 master인걸 확인하고 새 브랜치를 만듭니다. hotfixes

- 원격 브랜치 푸시도 합니다.

hotfixes 브랜치 작업
- 브랜치가 hotfixes로 잡혀있는걸 확인하고, 이제 버그를 잡습니다. 버그는 README.md 파일에 있다고 가정하고 코드를 수정합니다.

- 버그를 잡았으면 이제 commit push 해 줍니다.

- push가 완료되었네요.

hotfixes 브랜치 -> master 브랜치로 merge
- 버그를 다 잡고 push까지 완료 되었다면 이제 master 브랜치에 merge를 시켜줘야 합니다. 최종적으로 production으로 나가는 소스는 master 브랜치에서 진행될 테니까요.
- 먼저 체크아웃 브랜치를 master로 변경해줍니다.

- 이후 hotfixes 브랜치를 우클릭하여 'Merge hotfixes into master' 항목을 통해 merge 작업을 해줍니다.

- 물어보면 쿨하게 ok 해주시고, (저는 일단 바로커밋 체크항목은 빼고 진행했습니다.)

- master 브랜치 push하라고 뜨니깐 push 해주고


- 새로운 production으로 나갈것이니 태그도 달아줍니다.

hotfixes 브랜치 -> develop 브랜치로 merge
merge 작업은 master 쪽에만 해주는게 아니라 develop 브랜치에도 해줘야 합니다. 이 부분을 누락하면 정말 나아아아아아중에 발견될지도 모릅니다.
- master에 merge 할 때랑 동일하게 우선 develop 브랜치를 checkout 합니다.
- hotfixes 브랜치 항목을 우클릭하여 merge 합니다.

- hotfix에서 수정한 내용이 develop으로 들어오면 commit push 합니다.


- git-flow에서 hotfix 아래 부분에 대한 작업을 해보았습니다.

5) relese 브랜치
아까 개발 중이던 개발자 A, B가 있었죠? 개발 기간이 달라서 개발자 A 기능이 먼저 완료되었다고 합니다. A가 만든 feature 를 먼저 반영을 시키려고 합니다.
- 단위테스트가 완료되었다고 보고 develop -> release 브랜치로 올리도록 하겠습니다.
- release 브랜치는 제품 출시 전, 다양한 테스트를 해보도록 하는 브랜치로 사용됩니다.
releas 브랜치 생성
- 개발자 A가 feature 브랜치에서 develop 브랜치를 체크아웃받습니다.

- 그동안 develop에 올라온 내용들이 있으니 pull을 한번 받아줍니다.
- pull을 받았으면 아까 여러번한 merge 작업을 개발완료한 feature로 해줍니다.

- merge가 정상적으로 수행되었으면 commit -> push!

- 자 이제 다시 develop 브랜치 -> release 브랜치 가지치기!
- new 브랜치 release 브랜치

- push! 원격 레포지터리 생성

- 그리고 이제 테스트를 진행합니다....
release 브랜치 -> develop 브랜치로 merge
- 개발자 A에게 새로운 기능을 만드는 mission이 주어졌습니다.
- release 브랜치를 다시 develop 브랜치와 merge를 해주고,
- develop 브랜치에서 또 새로운 feature 브랜치를 생성하겠습니다.
- develop checkout, merge, push

feature 브랜치 생성
- 개발할 feature 브랜치 windimill을 생성합니다. 원격으로 push도 해줍니다.

- 파일을 만들어 개발을 하고

- commit, push 합니다.

release 브랜치 간단한 bug fix
- 만일 release 단계에서 발생된 버그가 있으면 굳이 개발로 안내리고 간단하고 바로 수정작업하여 commit 합니다.
- 일단 sourceTree에서 다시 release 브랜치로 체크아웃을 합니다.

- release 하려 했던 fireball 기능에 수정해야할 버그가 있어서 수정합니다.

- commit 하라고 뜨네요. commit, push Go!!!

release 브랜치 -> master 브랜치로 merge
- 이제 정말 완벽하다 싶으면 master 브랜치로 merge합니다.
- merge 하는 방법은 이제 익숙해졌을거라 생각합니다.
- 만약 현재 로컬 저장소에 master브랜치가 없다면 하단에 원격 항목에서 master 브랜치를 checkout 받아줍니다.


- master 체크아웃 -> merege release

- master에 push

- product 나갈꺼니깐 tag 한 번 달아주고

- 아까 master 브랜치에 tag를 달아줬는데 push를 안해서 없어졌네요. 다시 tag를 달아줍니다.

- 이렇게 태그까지 완료 하고 실제 해당 프로젝트를 가지고 프로덕트를 만들어 냅니다.
release 브랜치 -> develop 브랜치로 merge
- 만약 release 단계에서 bug fix가 있었다면 다시 develop 브랜치에 merge하는 작업을 해주어야 합니다.
- develop checkout, merge release, push

4. feature Branch 합치기
1) feature 브랜치들 -> develop 브랜치
자 이제 아까 개발자 A, B군이 모든 개발을 완료했다고 하고 모든 작업물을 develop에 올리려고 합니다.
- 그전에 수정할게 있으면 한번더 작업을 해주고, 개발자 A

- 개발자 B

- 모든 push가 끝났으면 clean한 상태에서 develop 브랜치를 checkout 한 후, 개발된 feature 브랜치들을 merge 합니다.
- 하나씩 merge commit push

- 두번째 feature 브랜치도 merge commit push

2) develop 브랜치 -> release 브랜치
- 운영에 올리기전에 테스트를 위해 release에 merge!


3) release 브랜치 -> master 브랜치 merge
- 테스트 상에 문제가 없으면 master로 merge, push!

4) release 브랜치 -> develop 브랜치 merge
-
새로운 개발을 위해 다시 develop 브랜치로 merge, push!

-
feature 브랜치들을 모두 합치고 master까지 보낸 git flow 항목을 따라했습니다.

-
완료된 상태의 sourceTree 그래프입니다.

5. Branch 삭제
1) 메인브랜치와 보조브랜치
git flow 전략에서는 메인브랜치와 보조브랜치를 나누고 있습니다.
메인브랜치
- 별도의 삭제 없이 계속 유지하는 브랜치
- master, develop
보조브랜치
- 사용한 이후 할 일이 끝나면 삭제하는 브랜치(사용할 때는 재생성)
- feature, release, hotfixes
보조 브랜치들이 계속 생겨나면 헷갈릴 테니 필요없는 브랜치는 삭제해보도록 하겠습니다.
2) 보조브랜치들 삭제
release 삭제
- sourceTree에서 원격 항목에 우클릭하여 삭제합니다.


hotfixes 삭제
- hotfixes 삭제합니다.

feature 삭제
3) 삭제 확인
- github에서도 깔끔하게 삭제가 되어 2개의 main 브랜치만 존재하게 되었네요.
- 깔끔해지니깐 기분도 맑아지네요.

git-flow 전략에 대해서 예제를 통해 연습해 보았습니다. 실제로 업무를 하게 되면 회사마다 CI/CD 자동화가 되어있는 곳도 있으며, fork, pull request에 대한 개념도 있습니다. 기회가 된다면 또 올리도록 하겠습니다.
참고사이트
https://techblog.woowahan.com/2553/