Pull Request 와 Code Review
지난 글에서 Github Organization을 만들고 원격 저장소에 Commit History를 Push하기까지 했다.
공동 작업할 수 있는 환경이 갖춰졌다. 이제 동료들과 '너도나도 여기저기에서' commit하면서 프로젝트를 진행 해보자.
로컬 저장소에서 브랜치를 만들어서 작업한 commit을 master에 Merge 했었다.
배포나갈 완제품에 불완전한(혹은 검증되지 않은) 변경사항을 적용한다면 어떻게 될까? 어디선가 사고가 터지고 말것이다. 그렇기 때문에 master와 격리된 공간에서 수정하고 테스트하기 위해 branch를 만들어서 작업을 한다.
약속하자. master 손대지 않기로.
<Git&Github은 왜 사용하는걸까 3 branch편> 중에서
A: 맞다. 그런데 같이 작업하는 동료들이 생기면서 상황이 조금 달라졌다. 로컬에서는 master에 병합도 하지 말자. 동료들의 리뷰를 받은 후에 Merge 해야한다. 이를 위해서 Github에서는 Pull Request 기능을 제공하고 있다.
Pull requests let you tell others about changes you've pushed to a branch in a repository on GitHub.
풀리퀘스트는 당신이 변경한 내용에 대해서 다른 사람들(동료)에게 말해준다.
<About pull requests> 중에서 출처: github.com
투박하게 표현하면, "여러분! 제가 Commit을 했습니다. master에 Merge해도 될까요?" 라고 알리는 활동이 Pull Request이다. 줄여서 PR(피알) 지금부터 PR이라고 표현하겠다.
PR은 아래 그림처럼 생겼다. 작업 제목(1) + 내용 설명(2) + Commit Log(3) + 리뷰어(reviewer)는 누구(4) 등등의 내용이 포함돼있다. 거두절미하고 한번 만들어보자.
로컬저장소에서 master에서 분기하는 브랜치 pr-practice를 만들어보자.
pr-practice.txt 파일을 새로 만들어서 아무거나 적은 다음에 커밋을 해보자.
~/my-git-project$ git checkout -b pr-practice // -b 옵션을 주면 브랜치를 만들면서 이동한다.
(파일 생성 -> 커밋 생략...이제 배웠으니 알아서 해보자.)
로컬 브랜치의 commit history를 원격 저장소로 Push를 하자.
~/my-git-project$ git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin pr-practice
'no upstream branch' 라고 에러가 났다. 'upstream branch가 없다' 다시 말하면 무슨 브랜치로 push를 할지 모르겠다는 말이다. (upstream branch는 로컬브랜치와 연결된 리모트 브랜치다.)
그 아래에 친절하게 어떻게 하면 좋을지 알려준다. 복붙하자.
(upstream 브랜치 pr-practice로 push 하는 명령어다. 없으면 알아서 만들어진다.)
~/my-git-project$ git push --set-upstream origin pr-practice
........
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote:
remote: Create a pull request for 'pr-practice' on GitHub by visiting: (5)
remote: https://github.com/anonym-org/foo-bar-project/pull/new/pr-practice
remote:
To github.com:anonym-org/foo-bar-project.git
* [new branch] pr-practice -> pr-practice (6)
console output중에서 두개가 눈에 들어온다.
주소로 가서 pull request 만들라고 알려줬다. (5)
리모트 브랜치 새로 만들었단다. (6)
여튼 잘 올라갔단다. Github으로 돌아가서 새로 고침을 해보자. pr-practce가 recently-pushed됐다고 하는 노란색 박스가 상단에 보인다.
박스 오른쪽에 있는 Compare & pull request를 클릭하면 Pull Request를 작성하는 페이지가 나온다.
PR의 제목과 설명을 적고 Create pull request를 누르면 Pull Request가 만들어진다.
아! 리뷰어들도 꼭 추가하자. 그러면 리뷰어들에게 알람/이메일이 간다.
A: PR의 제목은 내가 작업한 내용을 한문장으로 요약해서 적도록 한다. 만약 한문장으로 요약이 안된다면 PR 사이즈가 크다는걸 의미할 수 있다. PR을 분리하는걸 고려해보자. (커밋 메시지 작성도 똑같다.)
A: '1PR 1기능' 이라는 말이 있다(=내가 만든말). 1개 PR에는 1개 기능 변경/추가만 포함하는게 좋다는 의미다. 리뷰하기도 좋고 PR후에 만들어지는 Commit을 관리하기도 좋다. (나중에 문제 생기면 어떤 PR에서 발생했는지 찾기 쉬우니까.)
정리하면
1. 1개 PR에서는 기능 변경/추가를 1개만 포함하자.
2. 제목은 함축적인 내용으로 한문장으로 적자. (영어로 적을 경우 동사로 시작하면 좋다.)
A: PR 제목이 짧아서 적지 못했던 구체적인 내용/사정/정황/맥락/사진자료 등을 넣어서 리뷰하는 사람의 이해를 도와줄 수 있는 내용을 적자. 그렇다고 너무 길게는 쓰지 말자. 너무 길면 안보게 된다.
PR을 만들어봤으니 이제 제3자 입장에서 리뷰를 해보자. 리뷰하는 방식은 조직마다 개인마다 다르다. 개인적으로 교과서적이라고 생각하는(=니 생각) 리뷰 방식을 소개해본다.
언어영역 문제 풀이처럼 너무 당연해서 소름이 돋는다.
상단탭의 Commits (7) 를 눌러서 Commit들이 있는지 살펴보자. 커밋 히스토리를 보면 PR 작업의 흐름과 내용이 눈에 들어온다. (Commit message가 중요한 이유중 하나다.) 커밋의 상세내용을 보고 싶다면 보고자하는 커밋을 클릭해서 살펴본다.
만약 Commit message로 파악하기 힘들다면 이 단계는 대충보고 넘어가자.
상단탭의 File changed(8) 를 눌러서 변경된 파일별로 한줄한줄 봐가면서 리뷰를 시작하자. 코멘트하고 싶은 부분이 있다면 해당 라인을 눌러서 커멘트를 남기거나 재수정을 요청한다.
좋은 코멘트는 내용에 근거가 있고 구체적일수록 좋다.
1. (가장 명확한 방법임) 예시 Code를 적어준다.
2. 기술문서나 구체적인 사례를 인용한다.
3. 마지막으로 핵심만 간단히 남긴다.
4. 리뷰에 감정을 싣지 말자.
마지막으로 PR을 승인할지 재변경요청을 할지 결정하면 된다. 훌륭한 코드고 master에 병합되도 문제가 없다면 과감하게 Approve를 눌러주자. 반면 PR에서 수정해야할 부분이 있다면 Request changes를 누르고 그 이유를 적어주자.
코드 리뷰는 비난에 목적을 두는게 아니라 기술적인 피드백을 목적으로 한다는 점을 기억하기 바란다. 코드를 비난할지언정 사람을 대상으로 하는건 감정 싸움으로 번지기 쉽다. 리뷰를 받는 입장에서도 피드백을 감정적으로 받아들이지 말자. 코드를 리뷰한거지 사람을 리뷰한게 아니다. 내가 코드는 아니다라는걸 기억하자.
PR을 Merge 하는 방법은 3가지가 있다.
PR의 commit들이 "Merge pull request #1 from anonym-org/pr-practice" 메시지와 함께 master의 Head commit으로 들어간다.$git merge 명령이랑 똑같다. (메시지는 수정할 수 있다.)
master에 병합될 때 commit log들이 지저분하게 들어가서 개인적으로 비추한다.
PR의 커밋로그들이 master에 재정렬돼서 병합된다. PR에서 작성한 모든 커밋들이 master에서 관리돼야 한다면 Rebase and merge로 병합하는 방법을 추천한다. 로컬에서 작성된 모든 커밋로그들까지 추적할 수 있는 장점이 있다. 대신 커밋로그를 로컬에서부터 성의 있게 잘 정리해서 작성해야 한다. 안그러면 커밋히스토리가 지저분해진다.
(Merge와 Rebase의 차이점 대해서는 Merge 와 Rebase의 차이점에 대한 개인적 정리 참고)
개인적으로 제일 깔끔한 방법이라고 생각해서 선호한다. PR의 commit log들을 한개로 추려서 master에 병합하는 방법이다. Squash and Merge 를 클릭하면 PR 제목으로 된 1개의 커밋로그가 master에 병합된다.
PR = Commit 인 셈이다.
앞서 얘기했듯이 '1PR 1기능'이 가장 이상적이라고 생각한다. 따라서 기능의 관점에서 봤을 때, PR을 하나의 Commit으로 간주하는게 맞지 않을까? 문제가 발생했을 때도 우선 PR단위로 추적하고 복구하기도 좋다.
커밋 로그를 관리하는 방법에 따라 위 3개중 어떤 기능으로 병합할지를 결정하는게 좋다. 대신 동료들과 통일하는걸 추천한다. 누구는 Squash Merge 하고 누구는 Rebase Merge하면 일관성있게 커밋로그를 관리하기 어렵워진다.
commit 응용편에서 소개했던 $git revert 와 동일하게 PR도 되돌릴 수 있다. (10) Revert를 누르면 PR의 모든 commit이 되돌려진다.
(11) PR의 리모트 브랜치도 지울수 있다. PR 병합 후에는 필요 없으면 지우도록 하자. 존재의 이유를 모르는 브랜치가 많아지게 되면 관리하기 어려워진다.
Git&Github은 왜 사용하는걸까 를 주제로 한 글은 여기까지. 강의 자료로 쓰기 위해서 쓰기 시작했던 글인데 내 스스로도 Git과 Github에 대해서 정리하는 좋은 계기가 됐다. Git에 대한 설명을 하는 글이었지만 이론적인 접근은 최소한으로 했다. 대신 Git의 순수한 사용자의 관점에서 서술하고자 했다. 개인적인 경험에서 나온 버전 관리 방법들을 제시했다는 점을 알았으면 좋겠다.
Git과 Github을 사용하는 방법은 무궁무진하다.
명령어도 많고 기능도 많고 사용하는 절차도 다양하다. 사용해보면서 필요한 부분을 보완해나갔으면 한다. 본인의 경우에는 글에 적은 내용이 git 과 github을 사용하는 모든것이다. 물론 상황에 따라 다르겠지만 대부분의 경우에 그렇다.
git 과 github은 최대한 단순하게 사용하자. 앞선 글에서도 얘기했지만 복잡한 명령어들을 자주 입력하고 있다면 잘못된 방법으로 사용하고 있을 가능성이 크다. 어떻게 사용해오고 있는지 스스로 돌아보고 단순화한다면 작업 생산성도 더욱 올라갈 것이다.
끝