-
git으로 협업하는 방법팁 2021. 10. 16. 23:05
git 관련 팁을 적었던 저번 글에 이어서 이번에는 "git으로 협업하기"에 대해서 다뤄보고자 한다. 내가 속한 조직에서는 git-flow 전략을 사용하고 있는데, 이 방법을 사용하면서 그동안 가지게 된 생각을 적어보려고 한다.
git-flow 전략에 대해서는 우아한형제 블로그의 "우린 Git-flow를 사용하고 있어요"에 정말 자세하게 소개가 되어 있다. git-flow가 아직 익숙하지 않은 분들은 이 글을 꼭 읽어보셨으면 좋겠다. git command와 함께 A-Z를 너무 잘 설명하고 있어서 내가 일일이 반복할 필요는 없을 것 같다. git-flow가 아직 익숙하지 않은 분들은 이 글을 꼭 읽어보셨으면 좋겠다. 우리 조직에서도 위 글에서 설명하고 있는 방식을 거의 그대로 따르고 있어서, 그동안 실천했던 프로세스를 정리하는 느낌으로 읽었다.
본 글에서는 위 설명에 좀 더 얹고 싶은 내용만 적어보려고 한다.
왜 upstream과 origin을 구분해서 사용하는가
보통은 upstream과 origin으로 구분하여 작업한다. upstream은 회사의 코드가 관리되는 곳이고, 이것을 각자 fork한 것이 origin이 된다. origin에 push한 뒤, upstream에 대해서 pull request를 열어서 코드 리뷰 후에 merge하는 절차를 따르는 것이 일반적이다.
굳이 이렇게 하는 이유는 무엇일까? 우선은 upstream에 바로 push하는 것이 위험하기 때문이다. fork repository에서는 어떤 짓을 하든 공용 코드에는 아무런 피해가 가지 않는다. 대부분의 재앙도 결국 복구는 할 수 있겠지만, 명령어 한 줄로 동료에게 피해를 끼칠 수 있기 때문에 미리 조심하는 것이 큰 것 같다.
upstream에 브랜치가 너무 많아지는 것을 방지하는 효과도 있다. Jira의 각 티켓마다 보통 feature branch를 만들게 되고, 이 외에도 다양한 이유로 이런 저런 브랜치를 만들게 된다. 만약 이런 브랜치들이 전부 upstream에 만들어진다면 브랜치가 너무 많아서 관리가 어려워질 것이다. upstream에는 master, develop, release, (여러 개발자가 함께 개발하는)feature, hotfix 등 중요한 브랜치들만 관리되는 것이 좋다. 이 외의 잡다하게 만들어지는 origin에 만들고, pull request를 통해 upstream의 중요한 브랜치에 merge하는 flow를 따르는 것이 좋다.
hotfix 브랜치는 무엇인가
글에서 hotfix에 대한 내용은 거의 생략이 되어 있어서 적는다. 보통은 정기적인 배포 일정이 있지만, 그 사이에 중대한 버그가 발견되거나, 긴급하게 적용되어야 하는 어떠한 수정이 있을 수 있다. 이런 경우에는 다음 배포 일정까지 기다릴 수 없어서 긴급 배포, 즉 hotfix를 하게 된다.
이때는 운영 환경에 배포하는 코드인 master branch를 베이스로 hotfix 브랜치를 만든 뒤, 원하는 작업을 한 뒤 push origin 해서 hotfix 브랜치로 pull request를 만든다. 코드가 merge되면, hotfix 브랜치를 master와 develop에 merge하고 master를 배포한다.
rebase를 할 수 있는 상황이라면 rebase를 하자
위 글에서도 깔끔한 히스토리를 위해 feature branch에서 rebase하는 것을 강조하였는데, 나도 rebase를 정말 좋아한다. 이미 완료된 작업들을 (현재 작업 중인)내 작업 앞으로 이동시켜 놓는 것이 깔끔하게 느껴진다. 함께 사용하는 branch에서는 히스토리를 변경시켜 버리므로 절대 하면 안 되지만, 혼자서 작업 중인 branch에서는 모두가 rebase를 애용했으면 좋겠다.
push upstream은 위험한 것 같다
위 글에서는 절차를 간단하게 정리하기 위해서 그랬을 수 있지만, 모두가 작업 중인 branch 자체를 push upstream하는 것은 좀 위험하다고 생각한다. 언제 누가 무엇을 왜 합쳤는지 이력을 남기지 않으면 현재 각 브랜치가 어떤 상태인지 한 눈에 알기 어렵고, 잘못된 merge로 인한 실수를 미연에 방지할 수도 없고, 문제가 생겼을 때 과정을 파악하는 것도 어렵다. 따라서 중요한 branch에서 merge를 하는 것은 로컬에서 하지 말고, pull request를 열어서 모두가 보도록 하는 게 더 좋다고 생각한다.
merge conflict는 연관된 작업자들이 모두 볼 수 있게 하자
글에서 merge conflict에 대한 언급은 없었지만, 다른 사람과 함께 작업을 하다 보면 자주 merge conflict를 만나게 된다. 종종 작업자가 알아서 충돌을 해결하곤 하는데, 만약 잘못된 변경사항을 택해서 해결를 할 경우 문제가 생긴 나중에 원인을 파악하고 수정하는 건 꽤나 성가신 일이다. feature branch에서 rebase하다가 잘못 resolve한 것은 코드 리뷰의 과정을 거치면서 잡아낼 수 있지만, branch끼리 merge하면서 잘못 resolve하는 건 정말 피하고 싶은 상황이다.
이럴 때는 반드시 내가 일으킨 충돌과 연관된 작업자들이 내가 resolve한 사항을 함께 검토할 수 있도록 해야 한다. 옆자리에 앉아서 또는 메신저를 통해서 함께 해결할 수도 있고, pull request을 만들 수도 있다. pull request를 만들 때는 어느 부분에서 충돌이 발생했는지를 리뷰어들에게 알려주는 것이 좋다. (파일 자체가 많을 경우 리뷰어는 도대체 중점적으로 봐야하는지 매우 곤란하기 때문에..)
이를 위해서는 2가지 정도 방법이 있는 것 같다. 첫째, 충돌을 해결한 후 git commit할 때 나오는 화면에서 충돌이 발생한 파일 리스트의 주석을 해제하는 것이다. 그러면 pull request에 그 파일 리스트가 함께 올라가서 리뷰어가 확인하는 데 편리하다.
둘째, 어느 파일의 어떤 부분에서 충돌이 발생했는지까지 친절하게 알려주는 방법이다. 이를 위해서는 다음의 스텝을 따르면 된다. 먼저 충돌이 발생한 그 상황에서 그대로 commit을 한다. 이러면 <<<<<, >>>>> 이런 표시까지 다 남게 된다. 이를 push origin 하고, commit id를 복사해둔다. 그 다음에 다시 merge conflict가 발생한 시점으로 reset한 뒤, 충돌을 해결하고 push origin 후 pull request를 만든다. 이때 아까 복사해둔 commit id를 함께 제공한다. 이렇게 하면 리뷰어는 보다 자세하게 충돌 사항을 확인하고 리뷰할 수 있게 된다.
코드 리뷰를 통해 발생하는 수정 사항을 반영하는 방법
코드 리뷰를 하게 되면 리뷰어의 제안에 따라 수정 사항이 발생하게 된다. 이때 깔끔한 이력 관리를 위해서 조금 더 신경을 쓰는 것이 좋다.
리뷰가 반영될 때마다 push --force를 할지 또는 별도의 commit을 계속 쌓을지 결정해야 한다. 만약 리뷰가 진행되면서 이전에 올린 작업 내용이 완전히 뒤바뀌어야 할 정도라면 push --force를 하는 것이 좋다고 생각한다. 이전 변경 사항은 거의 쓸모 없게 되어서 굳이 별도의 commit으로 남겨둘 필요는 없는 반면, pull request에서 리뷰어의 코멘트 이력을 보는 것은 좋으니까 close하지 않고 push --force를 하는 것이다.
반면 조금씩 리뷰가 바뀌는 것이라면 리뷰어가 before과 after을 쉽게 볼 수 있도록 하기 위해서 나는 별도의 commit을 쌓는 것을 선호한다. 애초에 같은 티켓의 작업이라도 commit을 쪼개는 것이 리뷰어에게 도움이 된다면 최대한 commit을 쪼개는 것도 선호한다.
하지만 이런 방법은 나중에 merge할 순간이 왔을 때 고민이 된다. 하나의 티켓에 대한 작업으로 많은 commit을 쌓게 되니, 나중에 cherry-pick이나 revert를 해야 하는 상황이 오면 꽤나 귀찮아질 수 있다. 나중에 다른 작업자가 commit 내용을 통해 작업의 히스토리를 파악할 때 더 어렵기도 하다.
이런 경우에는 squash merge를 사용하면 좋다고 생각한다. squash는 여러 개의 commit을 합쳐서 하나의 commit으로 만드는 방법이다. github의 pull request 화면에서 squash merge 옵션을 선택할 수 있다. 이렇게 하면 전체 작업을 아우르는 의미있는 commit을 남김과 동시에, pull request 화면에서는 commit 리스트를 보며 세부적인 히스토리까지도 파악할 수 있다.
개발 환경 배포용 브랜치의 필요성
위 글은 앱 개발 팀에서 따르는 flow를 설명한 것이라서 이 부분이 생략되어 있는 것 같은데, 적어도 서버 팀에서는 베타 환경 배포용 브랜치가 하나 더 필요하다. 아직 이번 배포 일정에 포함되는 건이 아니고 QA 대상도 아니지만, 앱이나 프론트 팀에서 개발을 진행하기 위해서 서버 코드가 필요한 경우가 있다. 배포용으로 엄격하게 관리하는 코드는 아니지만 베타 환경에 어떤 코드가 있는지 관리가 필요하므로, 이 경우에는 별도의 브랜치를 만들어 관리해야 한다.
'팁' 카테고리의 다른 글
Git으로 실수했을 때 살아남기 (0) 2021.10.03 Intellij 폰트 색깔 바꾸기 (Intellij color scheme) (0) 2021.08.25