처음으로 팀 프로젝트에 참여하면서 코드 공유, Pull Request를 통한 협업, 브랜치 병합 등 Git을 제대로 활용하는 경험을 할 수 있었다. 첫 주차 미션이 종료되고 아래와 같이 2 가지의 문제점을 보완해야겠다는 생각이 들었고, 이를 정리한 해결 방안을 공유해보려 한다.
첫 주차 미션에서 느낀 팀 코드 저장소의 문제점
1. 프로젝트 성향을 고려한 브랜치 전략 부재
2. main, develop 등 공유 브랜치의 보호 규칙 부재
여러 개발자가 하나의 저장소를 사용하는 팀 프로젝트 환경에서 브랜치 관리를 효과적으로 하기 위하여 다수의 브랜치 전략들이 알려져있다. 본 글에서는 잘 알려져있는 브랜치 전략들과 NHN 컨퍼런스에서 소개된 깃 워크플로 사례를 참고하여 필자의 팀에 적합한 브랜치 전략을 세워나가는 과정을 이야기할 예정이다.
본 팀 프로젝트는 4 일동안 주어진 과제를 구현하고 배포까지 해야 하는 단기간 프로젝트이다. 특이 사항은 기능을 나누어 개발하는 것이 아니라, 팀원 각각 완성된 프로젝트(practice)를 개발한 후 가장 좋은 코드(best practice)만 선별하여 하나의 프로젝트로 완성시켜야 하는 것이다. 첫 주차에서 브랜치 전략 부재의 문제점을 느낀 시점은 팀원 개별의 practice 코드를 관리할 때였다. 기존에는 팀 원격 저장소를 팀원들이 fork
하여 practice 코드를 develop
브랜치로 Pull Request를 통해 공유하였다. 이 경우 팀 원격 저장소에서 각 코드를 보관하지 않아 PR이 close되면 확인하기 어렵다는 단점이 있었다. 또한 practice 코드와 best practice 코드 모두 develop
브랜치에 PR되어 이를 구분하기 어려웠다.
따라서 새로운 브랜치 전략은 아래 두 가지의 큰 기준을 바탕으로 4 개의 브랜치와 서브 브랜치들로 구성하였다.
- 팀 원격 저장소를
clone
하여 모든 코드를 팀 저장소에 공유- main: 배포를 담당, develop: best practice 코드 담당, practice: 팀원 개별 개발 코드 담당
프로젝트 초기 설정부터 배포까지의 과정을 본 프로젝트의 브랜치 전략을 활용하여 설명하면 다음과 같다.
main
브랜치에서 완료한다.practice
브랜치를 분기하고, 팀원들은 practice
브랜치에서 각자의 이름/깃헙 아이디로 된practice sub-branch
를 분기하여 practice 코드를 작성한다.practice sub-branch
에서 개발이 완료되면 practice
브랜치로 PR을 올려 토론 후 best practice를 선정한다.develop
브랜치를 분기한다.develop
브랜치에서 기능/issue 별로 develop sub-branch
를 분기하여 선정된 best practice를 바탕으로 코드를 작성한다.develop sub-branch
에서 개발이 완료되면 PR을 통해 코드 리뷰를 받고, develop
브랜치에 코드를 merge하고 해당 브랜치를 삭제한다.main
브랜치에서 develop
브랜치의 코드를 merge하여 자동 배포가 이루어지도록 한다.main
의 배포된 코드에 문제가 생긴 경우 hotfix
브랜치를 생성하여 버그를 고친다.main
develop
브랜치로 merge하고 해당 브랜치를 삭제한다.practice sub-branch
들을 모두 살려두는 방식을 사용하여 나타난 단점이다.hotfix
브랜치 사용은 과도할 수 있다.팀 저장소를 운영하다보면 브랜치가 실수로 삭제되거나 PR이 아닌 다른 방식으로 커밋이 추가되는 등 예상치 못한 문제가 발생할 수 있다. 필자의 경우 팀원들의 브랜치 생성을 가능하게 하기 위해 팀 멤버 권한을 Read(clone, pull 가능)에서 Write(clone, pull, push 가능)로 변경하였다가 PR되지 않은 코드가 머지되어 보호 규칙의 필요성을 느끼게 되었다.
Branch Protection Rule는 팀의 규칙으로 설정하거나 저장소별로 구분하여 설정할 수도 있다. 공식 문서와 다음 블로그 글을 참고하여 본 프로젝트에서는 3 개의 브랜치(main
develop
practice
)에 규칙을 설정해보려 한다.
develop
은 팀의 주요 개발이 이루어지는 브랜치이므로 다른 브랜치보다 더 빡빡한 규칙을 두었다. 코드 병합을 위해서는 PR을 생성하여 2 명 이상의 코드 승인이 필요하고, 테스트 코드를 모두 통과해야 하며, PR 리뷰가 모두 해결되어야 한다. 조건이 달성되지 않으면 아래와 같이 merge 버튼이 비활성화되어 있는 것을 확인할 수 있다. 참고 사항으로 테스트 코드에 대한 CI는 GitHub Actions를 사용해 다음 글에서 구현해두었다.
마지막으로 PR된 코드를 merge할 때 사용할 수 있는 세 가지 옵션을 알아보자. PR 페이지에서 아래와 같이 3 가지의 병합 방법을 선택할 수 있고, 자세한 개념은 공식 문서와 다음 블로그 글에서 잘 설명해주고 있다.
각 팀원이 개발한 best practice의 서브 브랜치로부터 develop
브랜치에 출시할 코드를 병합하는 과정을 예를 들어보자. 일반 merge
옵션을 사용할 경우 서브 브랜치의 커밋들 참조 + 머지 커밋이 추가된다. squash
옵션을 사용하는 경우 스쿼시 머지 커밋만 추가되어 develop
브랜치를 깔끔하게 관리할 수 있다. rebase
옵션을 사용하는 경우 서브 브랜치 커밋들만이 추가되어 마치 하나의 브랜치에서 작업한 것과 동일한 결과물을 얻을 수 있다.
다수의 개발자가 참여하는 팀 프로젝트의 경우 squash
를 사용하여 주축이 되는 브랜치를 깔끔하게 관리한다고 한다. 지난 1 주차 미션의 경우에도 main
브랜치에 무려 128 개의 커밋이 쌓여 이력 확인이 어려운 문제가 있었다. squash
를 사용하면 기능에 따라 커밋 개수를 줄일 수 있는 장점이 있으나 무한 merge commit 지옥에 빠질 우려가 있다고 한다. 개인 개발단에서 rebase
등 명령어를 통해 커밋을 합치는 방법도 있다고 하니 이 옵션에 대해서는 팀프로젝트에 직접 적용해보며 결정하는 편이 낫다고 판단하였다.