ecsimsw

깃린이를 위한 브랜치 전략 / 깃으로 협업하기 본문

깃린이를 위한 브랜치 전략 / 깃으로 협업하기

JinHwan Kim 2021. 7. 17. 05:52

저는 현업을 경험해본 적 없는 학생입니다..

내 브랜치 전략을 소개하기 앞서, 아직 현업에서 일해본 경험이 없는 아무것도 모르는 학부생이 쓴 글임을 미리 알리고 싶다. 현업과 괴리가 크거나 정확하지 못하고, 이상한 규칙도 많을 것 같아 조심스럽다. 그래서 'A는 B다'의 문장보다는, '~하는 것을 좋아한다.' , '~ 하는 편이다.'와 같은 내 생각이나 경험 위주의 정보가 9할일 것 같다. 

 

이 글은 내 후배들을 위해서 쓰게 되었다. 2학년 후배들이 깃으로 협업을 해보고 싶은데, 공부 방향을 못 잡고 방법을 물어보는 경우가 많았고, 부족하지만 내가 깃으로 협업한 경험과 조심해야할 팁을 정리해주고 싶었다.

 

0. 기본적인 키워드는 구글링으로!

대신 기본적인 키워드는 알고 오는 것이 숙제다. 자바로 치자면 '협업을 위한 나만의 자바 코딩 규칙'을 알려주고 싶은 거다. 자바 문법은 알고 와야 한다. 

 

'log, status, commit, push, pull, fetch, clone, checkout, merge, (옵션 : reset, revert, pull request, fork)'

 

물론 나도 친절히 위 키워드들을 하나씩 정리해주면 좋겠지만, 훨씬 깔끔하고 정확하게 정리해놓은 자료들이 많기 때문에, 정리하는 나에게도 비용이고 읽는 독자에게도 마이너스라고 생각한다.

 

1. main / develop / feature

나는 보통 브랜치를 '주 브랜치'와 '보조 브랜치'로 나누고 있다. 주 브랜치는 프로젝트 도중에 삭제하지 않는 브랜치고, 보조 브랜치는 프로젝트 도중 수시로 파생되고, 삭제되는 브랜치를 말한다. 

 

주 브랜치로 main, develop, feature를 사용하고 있다. main은 출시될 수 있는 상태, develop은 출시 전의 상태 또는 개발 기능을 합치고 테스트하는 상태, feature는 기능을 개발하는 브랜치이다. 추가로 급한 에러가 생기는 경우 hotfix라는 브랜치로 버그를 수정하고 main 또는 develop에 바로 PR을 쏘기도 한다.

 

이렇게만 말하면 어렵겠지만 실제 작업 예시를 보면 또 그렇게 어렵진 않다. 예를 들면 내가 속한 프로젝트에서 로깅 설정을 맡았다고 하자. 그럼 나는 develop에서 따와 'feature/logging'이라는 브랜치를 생성하고 해당 브랜치에서 작업을 시작하게 된다. 여기서 feature/logging이 보조 브랜치이다. logging 작업을 위해 develop에서 파생해서 작업을 마치면 바로 삭제하는 것이다.

 

2. PR, 이슈 단위 작업과 문서화

작업을 마치면 develop으로 PR을 쏘고 다른 팀원들의 확인을 받는다. 여기서 코드 리뷰 진행되고, 팀의 규칙에 따라 몇 명 이상 approve해줄 때까지 merge를 못 할 수 있다. 신나게 까이고, 신나게 자기 코드의 근거를 말하는 그런 시간을 갖게 된다.

 

 

 PR이 merge가 되면 'close #38' 이 38번 이슈를 자동으로 닫아준다. 이슈를 정리함과 동시에 팀원들에게 '나 이거 해왔어요!!' 라고 알려주는 역할을 한다. 프로젝트가 커지면 사실 다른 사람이 뭐했는지, 어떤 기능을 구현했는지 파악하는 것조차 큰 비용일 테니 말이다.

 

그 아래 'wiki: 우리팀 로깅 설정'은 해당 작업을 하면서 생긴 공유가 필요한 정보를 팀 문서 저장소에 저장했음을 표시한 것이다. 이 PR의 경우에는 github wiki에 팀 로깅 설정 규칙을 정리해주고 링크를 달아줬다. 

 

작업 단위는 이슈 단위로 진행하는 것을 좋아한다. 개발해야 할 것이 생기면 마치 수험생이 노트에 할 일 목록을 작성하 듯 이슈를 등록하는 것이다. 할 일 목록의 단위로 공부하고 하나씩 지워나가는 것처럼, 마찬가지로 이슈 단위로 작업하고 작업을 마치면서 하나씩 닫아 나가는 것이다.

 

이슈를 할당할 때는 라벨을 달아 급한 정도나 일의 포지션을 표시하기도 한다. 또 작업자가 정해지면 Assignees에 등록하여 작업자를 명시할 수 있다.

 

아래는 이번에 내가 등록한 이슈를 예시로 가져왔다. 작업이 필요한 이슈를 찾았으나, 다른 작업에 직접 처리하지 못하는 상황이라 내가 생각하는 작업 필요 부분을 꼼꼼히 기록하였다. 이후 다른 팀원들이 코멘트로 불필요한 부분을 잡아주거나, 더 필요한 부분을 추가해주면 작업자가 해야 하는 부분을 확실히 할 수 있다.

 

 

3. 깔끔한 History를 위한 squash merge

merge가 허락되어 develop으로 merge 할 수 있게된 상황까지 왔다고 하자. merge는 팀 규칙이 있겠지만, 나는 주 브랜치로 merge하는 경우, 보통 squash merge를 사용하는 편이다. squash merge를 하게 되면 commit history가 하나로 합쳐져 merge 된 브랜치의 로그에서 더 깔끔하게, 큰 작업 단위의 history를 볼 수 있게 된다.

 

 

 

4. Conflict는 어떻게... 

여기까지 이해했다면 질문이 하나 나오기 좋을 것 같다. develop에서 파생돼서 feature/a, feature/b 가 동시에 진행되면 develop으로 merge 될 때 충돌은 어떻게 하냐는 것이 그거다. 음 나는 처음 브랜치 전략을 공부할 때 그런 의문이 들었었다.

 

내가 찾은 정답은, 답이 없다는 것이다. 어쩔 수 없다. conflict는 어떻게 자동으로 뚝딱 될 수 있는 부분이 아니다. 결국 누군가는 충돌난 부분에 어떤 쪽의 코드를 반영할 것인가를 정해야 한다. 그래서 conflict를 최대한 피할 수 있는 전략을 생각하거나, 최대한 실수하지 않고 conflict를 처리하는 연습을 해야 한다. 나 역시 부족하지만 나름의 팁을 좀 주면 다음과 같다.

 

작업을 할당하는 사람

 

- 이슈를 최대한 작게 쪼개 브랜치 수명을 최대한 짧게 잡는 것이 좋다.

- 병렬로 처리되는 작업은 가능한 독립적인 작업을 할당한다.

 

일을 처리하는 사람

 

- 수시로 상위 브랜치와 싱크를 맞춰 작은 conflict를 처리해나가면서 작업하는 것으로, 가능한 큰 Conflict를 만들지 않는다.

- 할당된 작업 범위 밖의 코드나 History는 절대 건들지 않는다.

- reset을 하지 않는다. 꼭 어떤 포인트에서 작업해야 하는 상황이 생긴다면 revert를 이용한다.

 

많이 연습해보는 것이 좋을 것 같다. 연습 없이 코드가 머릿속에 없는 큰 프로젝트에서 풀기 어려운 conflict를 만나면 당황할 것이다.

 

5. Commit 메시지와 PR 메시지

메시지 규칙이 팀별로 있겠지만, 평소 따르고 있는 컨벤션은 다음과 같다.

 

- prefix : feat, chore, test, refactor, style, docs, fix

- subject : 짧으면서도 명확하게, 문장형이 아닌 단언형

- body : 가급적이면 제목만으로 충분하도록 노력, 불가피한 경우 body 역시 같은 규칙으로 작성 

 

앞서 말한 모든 것들이 다 중요하지만, 나는 commit 단위와 메시지를 엄청 엄청 중요하게 생각하고 있다. 나한테 커밋은 작업이고, 커밋 메시지는 작업의 이름, 커밋 내역은 곧 작업 히스토리이다.

 

그래서 더 세세하게 작업을 백업하기 위해 commit 을 작은 단위로 갖는 것을 좋아하고, 어떤 작업을 했는지 깔끔하게 확인하기 위해 commit 메시지를 코드만큼이나 가독성 좋게 적는 것을 좋아한다. PR 단위와 메시지도 마찬가지다.

 

* feat: Job 생성시 유효성 검사 추가

* feat: DeleteHistory 생성시 유효성 검사 추가

* refactor: 코드 정리

* chore: conflict 처리

* fix: response 필드명 변경으로 테스트 실패 문제 처리

* refactor: 도메인 유효 검증 메시지 구체화

* refactor: 도메인 Exception 세분화 (#94)

* refactor: GpuServerServiceTest 오타 수정

* refactor: GpuServerAcceptanceTest 상속 자원 정리

* refactor: 도메인 Exception 세분화

* refactor(job): job 패키지 분리

* test: JobService 테스트 작성

 

6. 기본 중의 기본

특별히 팀 규칙으로 없어도 당연히 지켜야하는 기본 중의 기본이 있다. 처음에는 이런 규칙을 매번 생각하는 것이 번거롭다고 여겨질 수 있으나 몇 번만 해보면 곧 사람 간의 매너처럼 느껴질 것이다. 

 

먼저 본인의 개발 환경에 의해 생성되는 불필요한 파일이  저장소로 올라가진 않는지 확인한다. 이를 테면 내 경우에는 .idea, build 폴더, .gradle 등이 부산물로 생성된다. 이런 파일들은 저장소로 올리지 말아야 한다. 혹시 .gitignore 사용 방법을 몰라 매번 commit 파일에서 uncheck 하고 있다면 바로 구글링 해서 알아보자.

 

다음은 테스트 코드가 통과하지 않는 코드를 올리지 않는다. 커밋 단위로도 테스트가 전체 통과하는지 확인하면 좋지만 그게 아직 힘들다면, 반드시 PR 만큼은 모든 테스트가 통과하는지 확인하고 올려야 한다. 이건 정말 필수다. 테스트가 안되는 코드가 merge 되고 배포 서버에서 빌드 중 터진다면... 어우 정말 꼭 지켜줘야 한다. 

 

마지막으로 PR 전 프로젝트 코드 스타일을 확인하는 것을 잊지 말아야 한다. 빈 칸, 정렬 등 코드 스타일을 팀 규칙에 맞게 해서 PR을 쏴야 한다. 빈칸 하나 좀 더 있으면 어떻고 정렬이 안되어 있으면 어떨지 사실 불편하지 않을 수 있지만, 우리는 다른 사람들과 함께 코드를 짜고 있음을 알아야 한다.

 

또 코드 스타일을 확인한다고, 본인의 작업 부분 외의 다른 코드의 스타일까지 막 바꾸지 말자. merge 할 때 자잘한 스타일 차이로 귀찮아진다. 코드를 합치는 시점에서 한 번에 전체 코드 스타일을 정렬하는 것이 좋다.

 

더하여 Github actions로 PR 된 코드의 test를 포함한 빌드 가능 여부를 확인하고, 터지는 코드의 경우 merge를 막을 수 있다. 또 코드 스타일 역시 확인하여 팀 규칙과 안 맞는 코드의 merge를 막을 수 도 있다. 내 경우에는 코드 스타일까지 막은 경험은 잘 없긴 한데, 적용하고 싶다면 'Lint'를 키워드로 구글링 해보길 바란다.

 

 

 

7. 마무리 :: 규칙을 정하는 방향

이 글을 우연히라도 찾아 읽고, 마무리까지 스크롤을 내렸다면 정말 박수를 드리고 싶다. 아마 프로젝트를 깃으로 관리하곤 싶은데, 어떻게 해야 할지 전혀 감을 못 잡는 경우에서 답답한 심경에 이 글까지 찾았을 것 같다.

 

나 역시 그랬다. commit, push, pull 로 혼자 코드를 올리고 받아오는 것만 경험해봤지, 혼자 공부하면서 다른 사람과 협업을 위한 전략을 생각해본 적 없다. 그런 개념이 있는지 조차 몰랐다.

 

이렇게 아직 어떻게 협업해야 할지 감이 안 잡히는 팀에게 완벽한 규칙이 아닌, 규칙을 정하는 방향이 되었으면 좋겠다. 정 어려우면 일단 이 글의 규칙을 따라 해 보고, 점점 더 좋은 그 팀만의 규칙을 만들어 가셨으면 좋겠다. 그렇게 변형한 자신만의 규칙을 댓글이나 메일로 받으면 정말 행복할 것 같다.

 

추가로, 이 글은 계속 업데이트 될 예정이다. 경험을 쌓으면서, 나만의 팁을 늘리면서 하나씩 업데이트할 생각이다.

 

부족한 글 읽어주셔서 감사합니다.

 

 

 

Comments