🔥 기능요청 PR 시나리오
1. remote 리포지터리를 로컬로 clone 해온다.
2. pull 을 해서 상태를 최신화한다.
3. 개인 로컬에서 feat/#이슈번호 브랜치를 생성한다.
4. 기능 구현을 완료한 뒤 origin에 새로운 브랜치(현재 작업하고 있는 같은 이름의 브랜치)를 생성하고 push 한다.
5. origin에 있는 feat/#이슈번호 브랜치를 dev로 Pull Request를 보낸다. (같은 분야의 크루를 모두 리뷰어로 등록)
6. 리뷰어는 리뷰를 마친 뒤 수정할 사항이 없는 경우 approve 한다.
7. 마지막 approve를 한 리뷰어는 squash merge를 한다.
1. remote 리포지터리를 로컬로 clone 해온다.
이 때 우리 리포지터리의 default 브랜치는 dev로 설정되어 있기 때문에 clone 할 때 따로 지정해주지 않으면 dev브랜치를 클론할 수 있다.
$ git clone 리포지터리 주소
2. pull 을 해서 로컬에 있는 dev브랜치의 상태를 최신화한다.
pull을 하면 default로 설정된 브랜치의 내용이 자동으로 가져와진다. 그리고 그 내용을 나의 로컬 dev브랜치에 덮어쓴다.
$ git pull origin dev
3. 개인 로컬에서 feat/#이슈번호 브랜치를 생성한다.
$ git checkout -b feat/#2
4. 기능 구현을 완료한 뒤 origin에 새로운 브랜치(현재 작업하고 있는 같은 이름의 브랜치)를 생성하고 push한다.
$ git push origin feat/#2
5. origin에 있는 feat/#이슈번호 브랜치를 dev로 Pull Request를 보낸다.
같은 분야의 크루를 모두 리뷰어로 등록한다.
6. 리뷰어는 리뷰를 마친 뒤 수정사항이 없는 경우 approve 한다.
7. 마지막 approve를 한 리뷰어는 해당 이슈를 squash merge한다.
💊 시뮬레이션
readme 파일을 추가하는 작업을 시뮬레이션 해보면서 실제로 브랜치 전략을 어떻게 적용할 수 있는지, 다른 사람들과 협업을 어떻게 진행하는지에 대해 알아보자.
팀프로젝트에서 이슈나 PR을 맘대로 생성하고 클로즈하거나 닫으면 지울 수 없기 때문에 개인 레포에서 진행했다.
1. 리포지터리 클론
테스트 리포지터리를 새로 내 계정 아래 생성한 것이기 때문에 test용 readme 파일을 생성해서 최초 커밋을 main 브랜치에 생성해놓은 상태다.
현재 리포지터리의 브랜치는 main, dev가 있는 상태다. dev 브랜치는 main에서 생성한 브랜치다.
그리고 프로젝트 설정에서 dev 브랜치를 default로 설정해두었다.
$ git clone 리포지터리 주소
위 명령어를 통해 리포지터리를 클론해오자.
참고로 디폴트 브랜치를 변경은 프로젝트 Settings의 Default branch에서 가능하다.
2. 이슈 발급
readme 파일 작성이라는 제목으로 첫 이슈를 생성했다. 이 이슈는 #1번으로 등록되었고 Projects는 test Project로 등록했다. 상태를 Todo로 설정했기 때문에 칸반보드에는 Todo에 열린 이슈로 등록이 된다.
칸반보드 Todo에 위에서 오픈한 이슈가 보인다.
3. 로컬에 기능 브랜치 생성 및 push
// 브랜치 생성 및 체크아웃
$ git checkout -b docs
// 파일 수정
$ vi README.md
파일 수정1
// 커밋
$ git add .
$ git commit -m “docs: README 파일 수정 (#1)”
// 파일 수정
$ vi README.md
파일 수정2
// 커밋
$ git add .
$ git commit -m “docs: README 파일 수정 (#1)”
// 푸시
$ git push origin docs
위 명령어를 통해 파일을 생성하고 커밋한 뒤 리모트 리포지터리(origin)에 푸시할 수 있다.
리모트 리포지터리를 보면 새로 docs 브랜치가 생성되었고, docs had recent pushes less than a minute ago라는 문구가 뜨면서 Compare & pull request 버튼이 활성화된 것을 볼 수 있다.
그러면 커밋이 잘 올라갔는지 확인하기 위해 방금 푸시해서 새로 생성된 docs 브랜치의 커밋 내역을 보자.
새로 생성된 docs 브랜치의 커밋 내역이다. 로컬에서 커밋한 2개의 커밋 내역이 추가된 것을 확인할 수 있다.
4. PR 요청
default 브랜치를 dev로 설정해두었기 때문에 PR을 작성하는 페이지에 들어가면 PR을 날리는 base 브랜치는 dev가 된다.
그래서 기능을 구현한 브랜치에서(docs)에서 완성된 코드들이 모여있는 dev브랜치로 PR을 요청하는 것이다.
PR 내용에 아래와 같이 작성하면 해당 PR을 머지했을 때 작성된 이슈가 자동으로 close되니 이 기능을 활용하면 PR과 이슈를 관리하는데 더 수월하니 사용하자.
- close #이슈번호
5. Merge
PR을 확인하고 별다른 추가 변경사항이 필요해보이지 않는다면 merge하게 될 것이다.
merge의 방법은 총 3가지가 있다. 모두 비슷하지만 약간씩 다르다.
1. Create a merge commit
merge하려는 브랜치(docs)의 모든 커밋이 PR을 날린 브랜치(dev)에 모두 추가된다.
2. Squash and merge
하나의 커밋이 dev에 남는다.
merge하려는 브랜치(docs)의 모든 커밋이 하나로 압축되며 PR을 날린 브랜치(dev)에 추가된다.
3. Rebase and merge
잘 모르겠다.
우리 팀은 Squash and merge를 하기로 정했다.
위 화면은 Squash and merge를 누른 화면이다.
적혀있는 내용은 Squash and merge를 눌러 자동으로 생성된 내용이다. 그리고 지금 작성하는 내용이 PR을 날린 브랜치(dev브랜치)에 올라가는 새로운 하나의 커밋이 된다.
커밋 메시지는 PR에 작성한 제목 혹은 커밋 메시지로 자동으로 쓰여지는데 옆에 붙은 번호는 머지하려는 PR의 번호다. 만약 브랜치에 여러개의 커밋이 존재한다면 description에는 해당 브랜치에 있는 모든 커밋의 내용이 올라간다.
크게 수정할 필요는 없지만 우리 팀의 커밋 컨벤션에 따르면 앞에 []의 내용을 삭제하고 Confirm squash and merge를 해야한다.
PR을 머지하면 PR에 적어놓은 이슈가 자동으로 닫힌다.(너무 좋은 기능이다..) 그리고 닫힌 이슈는 또 자동으로 칸반보드에서 Done위치로 이동한다.
참고로 이야기하면 PR에도 Projects를 설정할 수 있다.
표시한 위치에서 PR의 Projects를 설정할 수 있는데 그렇게 되면 해당 PR을 칸반보드에 올릴 수 있게된다. 그러면 칸반보드에 모든 이슈와 PR이 등록이 될 것이다.
처음에 팀과 같이 시뮬레이션을 진행할 때는 PR에도 Projects를 추가했었는데 그러면 칸반보드에 과도하게 많은 데이터가 쌓일 수 있어 관리하기 어렵지 않을까 했다. 또 칸반보드에 있는 이슈에 merge된 PR의 링크가 자동으로 들어가기 때문에 칸반보드에서 PR까지 관리할 필요가 없다고 판단하여 PR에는 Projects를 넣지 않기로 결정했다.
6. branch 삭제 및 동기화
merge된 브랜치는 목표한 기능 구현이 마무리되었고 더 이상 필요하지 않은 브랜치이기 때문에 삭제를 하는 것이 좋다. 그래서 머지된 PR을 보면 Delete branch가 있다. 이를 클릭하여 손쉽게 리포지터리의 브랜치에서 삭제할 수 있다.
하지만 한 가지 문제가 발생할 수 있다. 리포지터리에서 브랜치를 삭제했지만 clone해서 관리하고 있는 로컬 리포지터리에서 $ git branch -a 명령어를 통해 브랜치를 확인해보면 삭제되지 않을 수 있다.
이를 해결하기 위해 $ git fetch -p origin 명령어를 통해 리모트 리포지터리와 로컬 리포지터리의 브랜치 정보를 동기화를 시켜줘야 한다.
📖 정리
- 새로운 기능을 구현하기 전에는 항상 로컬에 있는 dev브랜치를 최신화 시켜줘야 한다.
- $ git fetch -p origin
- 로컬의 dev 브랜치에서 로컬의 feat 브랜치를 생성한 뒤 올리는 커밋에는 이슈 번호가 들어갈 필요가 없다.
- 로컬 feat브랜치에서 작업 구현이 완료된 후 origin에 push할 때는 항상 로컬 feat브랜치명과 같은 브랜치를 origin에 생성하고 push 해야 한다.
- $ git push origin feat#N
- PR 요청 시 관련 이슈 번호를 내용에 작성해야 한다. 그래야 해당 PR을 머지할 때 관련 이슈를 close하는 등 자동으로 관리할 수 있다.
- squash merge할 때는 이전의 커밋들을 압축하여 하나의 새로운 커밋이 생성되는 것이고, 커밋 메시지에 PR번호가 들어간다. 이를 통해 main 혹은 dev브랜치에서 커밋 기록을 확인할 때 커밋 메시지에 등록된 번호를 통해 바로 해당 PR로 이동할 수 있다.
📚 참고
- 리포지터리가 로컬에 클론되어 있는 상태에서 새로운 브랜치를 생성했고, 이를 내 로컬에 업데이트 하고싶은 경우
- $ git fetch -p origin
- $ git remote update
- 여기서 둘 다 가능한데 fetch 가 좀 더 편한 것 같다.
- 리모트 리포지터리에 있는 브랜치로 체크아웃 하고 싶은 경우
- 원하는 브랜치 이름 : feat#2
- 로컬에 등록된 리모트 리포지터리 별칭 : origin
- $ git checkout -t origin/feat#2
- 로컬에 등록된 브랜치 삭제하고 싶은 경우 (삭제하고 싶은 브랜치에서 다른 브랜치로 체크아웃이 선행되어야 함)
- 삭제하고 싶은 브랜치명 : feat#2
- $ git branch -d feat#2
- 리모트 리포지터리의 브랜치를 로컬에서 삭제하고 싶은 경우
- 삭제하고 싶은 브랜치명 : feat
- 로컬에 등록된 리모트 리포지터리 별칭 : origin
- $ git push origin -d feat
- 리모트 리포지터리에서는 브랜치가 삭제되었는데 로컬에서 확인했을 때 삭제한 리모트 리포지터리가 남아있는 경우
- 리모트 리포지터리와 로컬(에서 가지고 있는 원격 서버의 브랜치 정보) 동기화 진행
- $ git fetch -p origin