Git을 이용하여 텔레파시 통하는 팀 만들기 : commit message와 commit log

 

해줌

 

저는 각자 컴퓨터 앞에서 따로 코딩하는 와중에도 함께 일하고 있다는 기분을 느끼고 싶었습니다.

함께 일하기 위해 우리는 회의를 잡고, 따로 이야기하고, 이메일을 쓰고, 일감관리 시스템을 사용하고 있습니다만, 우리(개발자와 데이터 사이언티스트)가 하는 가장 많은 시간을 쏟는 일 -코드를 생산하는 것-과는 동떨어진 작업이라는 느낌을 지울 수 없었습니다.

 

내가 만든 코드와 좀 더 밀접한 형태로 팀원들과 소통할 수 없을까요?

 

그래서 해줌 IT사업실에서 태양광 발전소 이상감지 시스템을 개발하는 과정에서 팀원들끼리 commit message, commit log를 이용한 소통 환경을 구축했고, 이를 통해 작업한 내용에 대한 공유와 소통이 촉진된 효과를 얻었던 이야기를 나누려고 합니다. (*편의상 commit message와 commit log를 커밋 메세지와 커밋 로그로 쓰겠습니다.)

Git을 비롯한 소스코드 버젼관리 시스템은 현대 소프트웨어 개발에서 필수적인 요소입니다. Git을 이용하면 소스코드를 여러 버젼으로 나누어 관리할 수 있고, 외부 저장소(GitHub, Bitbucket) 등을 이용해 코드를 공유할 수 있죠. 하지만 git은 커뮤니케이션 도구이기도 합니다.

 

 

 

 

 

 

Git에서는 커밋 메세지를 이용하여 작업 내용에 대해 해설을 붙일 수 있고, 커밋 로그를 통해 과거의 작업 이력과 현재 진행 중인 작업들(branch)의 현황을 확인할 수 있습니다. GitHub에서 제공하는 pull request기능을 활용하면 작업내용에 대한 리뷰도 진행할 수 있죠.

 

 

커밋 메세지와 커밋 로그는 git의 기본 기능입니다. 작업의 기본 단위가 커밋이기 때문에 커밋 메세지는 반드시 적어야 하고, 그 커밋이 쌓인 로그는 내가 싫어도 퇴사해도 남게 되죠. 이메일이나 회의와 달리 커밋은 개발을 하면서 어차피, 반드시 해야하는 일입니다. 이 과정을 조금만 더 신경써서 의사소통의 도구로 쓸 수 있다면 좋지 않을까요?

 

 

이상적으로는 그렇습니다. 하지만 현실은…

 

 

저만 그런거 아니죠?

 

 

개인 프로젝트를 할 때엔 이렇게 해도 큰 문제가 없을 수도 있습니다.
하지만 팀의 커밋 메세지라면 조금 곤란하죠. 커밋 로그도 마찬가지 입니다.

 

 

출처: https://chris.beams.io/posts/git-commit/

 

 

 

저희 프로젝트가 초반의 커밋 로그도 별반 다르지 않았습니다. 요컨데,  커밋 메세지와 커밋 로그가 의사소통 도구로서 전혀 기능 하지 못하고 있습니다. 커밋 메세지와 로그에 아무런 기능이 없고, 심지어 보기에 아주 지저분한 모습을 하고 있기 때문에 아무도 보지 않습니다.

 

이런 문제는 쉽게 개선되지 않습니다. 나 하나 커밋 메세지를 정성들여 작성한다 한들 티가 나지도 않고, 어차피 아무도 보지 않을 것을 알기 때문이죠. 모두가 커밋 메세지를 작성할 동기를 잃게 되고, 커밋 메세지와 로그는 늘 이런 상태로 남게 될 것입니다.

 

이럴 땐 “분위기”를 한번에 전환할 필요가 있다고 생각했습니다. 깨진 유리창 이론(https://en.wikipedia.org/wiki/Broken_windows_theory)을 알고 계신가요? 어떤 건물에 깨진 유리창이 많다면, 사람들이 그 건물의 유리창을 깨뜨릴 확률이 더 높고, 더 심한 파손이나 범죄로 이어질 수 있다는 내용입니다. 이렇듯 분위기는 사람의 행동에 영향을 미치게 되죠. 모든 것이 깔끔하게 진열되어 있는 곳 논산훈련소 라면, 저 같은 사람도 새로운 물건을 둘 때 무의식적으로 줄을 맞춰 두게 관물하게 됩니다.

 

 

출처 : 헤럴드 경제 (http://news.heraldcorp.com/view.php?ud=20150930000399&md=20151001094213_BL)

 

 

 

자, 그럼 git의 커밋 메세지와 커밋 로그를 유의미한 의사소통 채널로 바꾸기 위한 노력의 이야기를 들려드리겠습니다. 이미 git과 GitHub을 이용하여 깔끔한 워크플로우를 구축하신 팀도 많겠지만, 이제 시작하는 팀, 이제 팀의 워크플로우를 만들어가는 팀들께 도움이 되었으면 좋겠습니다.


 

1. 커밋 메세지

 

이 문제에 대해 생각하기 시작하자마자, “커밋 메세지를 깔끔하게 작성해주세요”라는 말은 의미가 없다는 것을 깨달았습니다. 어떻게 하는 것이 깔끔한 것이고, 또 어느 정도 깔끔해야 되는 것인지 사람마다 느낌이 다른 것입니다. 사실 이전까지의 상태도 각자 나름대로는 깔끔하게 한 것일 수도 있죠.

 

또한, 규칙을 지키게 하려면 규칙이 쉬워야 합니다. 즉, 팀원들이 커밋 메세지를 적을 때의 고민을 최소화하는 것이 필요합니다. 결국, “우리 팀은 커밋 메세지를 이렇게 적자”라는 가이드라인, 혹은 템플릿이 필요하다는 것을 알게 되었습니다.

 

좋은 커밋 메세지에 관한 좋은 글들이 많습니다. 대표적으로 https://chris.beams.io/posts/git-commit/ 을 번역한 https://item4.github.io/2016-11-01/How-to-Write-a-Git-Commit-Message/ 이 있는데요, 아주 도움이 되긴 했지만 여기 있는 조언들은 대부분 영어에 해당되는 것들입니다. (제목행을 명령문으로 쓰라거나..) 우리는 의사소통을 돕기 위해 한글로 커밋메세지를 작성하고 있기 때문에, 여기 있는 조언들 중 “1. 제목과 본문을 빈 행으로 분리한다.” “7. 어떻게 보다는 무엇과 왜를 설명한다” 와 같은 부분들만 참고했습니다.

 

우리 팀 커밋 메세지의 에시를 들어보겠습니다.

 

MLSYS-145: Simulator에서 운휴일수 반영 방식 변경

– bootstrap 방법으로 계산할 때도 일관되게 반영하기 위해Simulator._subtract_shutdown 삭제
– bootstrap 방법으로 계산할 때에 대한 shade, shutdown_day 반영결과를 테스트하는 코드 추가

 

혹은

 

BLD: Jenkins에서 pytest 실행을 위한 모듈들 requirements.txt에 추가

– Jenkins에서 pytest-cov, pytest-html, pytest-metadata 모듈들이 필요하여 추가함

 

“asdf”보다는 훨씬 낫죠. 우리의 커밋 메세지 템플릿은 다음과 같습니다.

 

<<일감 이슈 번호 혹은 커밋분류코드>> : <<커밋 메세지 제목>>

– 커밋 내용 1
– 커밋 내용 2

 

 

제목 줄이 있고, 한 줄 띄고 본문이 있습니다. 제목 줄에는 전체 커밋을 요약하는 내용이 들어가고, 본문에서는 ‘-‘을 글머리 기호로 사용하여 개조식으로 작업 내용을 서술합니다. 이게 전부입니다. 하지만 이런 가이드라인이 정해져 있는 것과 그렇지 않은 것에는 엄청난 차이가 있더군요. 규칙은 완벽한지보다 있는지가 중요한 것 같습니다.

 

<<일감 이슈 번호 혹은 분류>>도 중요한 부분입니다. 해줌 IT사업실은 JIRA를 이용하여 이슈관리를 하고 있습니다. 커밋에 해당하는 작업의 이슈 번호를 쓰고, 이슈 번호가 없을 때에는 커밋의 성격을 나타내는 분류 코드를 붙이도록 했습니다. 커밋 분류 코드는 Pandas 프로젝트의 가이드라인(http://pandas.pydata.org/pandas-docs/stable/contributing.html#committing-your-code)을 따랐습니다. 영어 대문자 3~4글자로 된 이 코드만 보면 해당 커밋의 의도와 종류를 한 눈에 알 수 있도록 했습니다.

 

ENH: (Enhancement) 개선하거나 신기능 추가
 BUG: 버그 수정
 DOC: (Documentation) 문서화 관련된 작업
 TST: (Test) 새로운 유닛테스트를 추가하거나 기존 테스트를 수정
 BLD: (Build) 빌드 프로세스 관련 코드 혹은 스크립트를 수정
 PERF: (Performance) 계산 속도의 개선과 관련된 작업
 CLN: (Cleanup) 코드를 정리하거나 리팩토링한 작업

 

커밋 메세지의 앞부분에 일관성을 부여하는 것이 의외로 커밋로그를 깔끔하게 보이도록 하는데요, 앞서 말씀드린 것처럼 “깔끔해 보이는 것”은 생각보다 매우 중요합니다! 무의식적으로 서로 규칙을 지키도록 하는 분위기를 만들어 내니까요.

 

그밖에 제가 생각하는 좋은 커밋 메세지를 위한 원칙들은 다음과 같습니다.

 

  • 어떤 문제(버그 등)를 해결하는 커밋이었을 경우, 그 문제가 무엇인지도 적는다.
    예) 그래프 출력 (x) ▷  2018년 이후에 그래프가 출력되지 않는 문제가 있어 그래프 출력 기능 복구
  • 가급적 어떤 클래스/함수/메소드를 수정했는지 정확하게 명시한다
    예) if문 제거 (x) ▷  ThisClass.__init__()의 if 구문 제거
  • 똑같은 커밋 제목이 존재하지 않도록 한다. 커밋 로그에는 첫줄(제목행)만 표시되므로, 이전 커밋과 똑같은 제목을 커밋을 하게 되면 커밋 로그의 정보량이 떨어집니다.

 


2. 커밋 로그 Commit log

 

잘 관리된 커밋 로그는 프로젝트의 진화에 대한 역사적 기록이 됩니다. 언제쯤에 누군가 이런 기능을 구현했었군. 고생이 많았지. 라던지, 이 커밋 뒤로 버그 고치는 커밋만 다섯 개야, 라던지, 프로젝트가 이렇게 진행이 되어 왔구나 하는 것을 한 눈에 볼 수 있게 합니다.

 

 

 

 

 

 

하지만 이런 커밋 로그는 전혀 그런 기능을 수행할 수 없죠.

 

일단 커밋 메세지를 쓰는 규칙을 정한 뒤에, 우리는 좋은 커밋 로그를 만들기 위해서 한 가지 원칙을 만들었습니다.

 

merge 커밋을 만들지 않는다

 

merge 커밋은 merge에 의해서 생기는 커밋입니다. 위 그림에서 “Merge branch ‘development’” 부분입니다. merge 커밋 자체가 기능적으로 나쁜 것은 아닙니다만, merge 커밋은 커밋 로그의 정보량을 떨어뜨리는 경향이 있습니다. 커밋 메세지도 따로 없지요. 게다가 자칫 잘못하면 merge 커밋이 꼬리에 꼬리를 물고 생기게 됩니다. 무한 merge 커밋 지옥에 빠지는 것이죠.

 

 

잠깐, 굵은 글씨는 난데?

 

도대체 뭘 어떻게 하면 이렇게 되는 건지 저도 모르겠지만, 아무튼 여러분께는 이런 일이 발생하지 않기만을 바랄 뿐입니다.(…) 결과적으로 merge 커밋이 지나치게 많으면 커밋 로그를 봤을 때 도대체 뭐가 진행되고 있는지 파악하기가 어렵습니다.

 

git에서 두 브랜치(branch)를 합치는 것을 merge라고 합니다. 정확히는 하나의 브랜치에 다른 브랜치의 결과를 반영하는 것이죠. 이 merge를 수행할 때, 추가적인, 기존에 없던 merge 커밋이 생길 수도 있고, 안 생길 수도 있습니다.

 

언제 merge 커밋이 생길까요? develop 브랜치에서 개발된 기능(=새로운 커밋)을 master 브랜치에 반영하는 경우를 예로 들어서 설명해보겠습니다. 여기선 편의를 위해 이름을 이렇게 붙인 것이고 보다 일반적인 브랜치 관계에서 모두 적용되는 이야기입니다.

 

 

 

 

위와 같이 분기점(B)를 기준으로 master와 develop에 각각 새 커밋이 존재하면, 둘을 합치기 위해 merge 커밋이 생성됩니다. 그리고 우리는 이 녀석을 만들고 싶지 않은 것이죠. merge 커밋 없이 merge를 하려면, 분기점 기준으로 master 브랜치에 새로운 커밋이 없어야 합니다.

 

 

 

 

위와 같이 분기점을 기준으로 develop에만 새로운 변경사항이 있다면, 그 변경사항을 단순히 master에 적용해주기만 하면 됩니다. develop의 변경 사항을 master가 따라잡기만 하면 된다는 의미에서 이런 merge를 fast forward라고 부릅니다. (https://confluence.atlassian.com/bitbucket/git-fast-forwards-and-branch-management-329977726.html) 그리고 이 때는 merge 커밋이 생성되지 않습니다.

 

master와 develop 양쪽에 모두 새로운 커밋이 있는 경우는 협업 환경에서 빈번하게 발생합니다. 내가 develop에 새 기능을 개발하며 커밋을 추가하는 동안 다른 사람이 버그를 수정했을 수도 있고, 다른 기능을 추가했을 수도 있죠. 이런 상황에서 merge 커밋을 만들지 않기 위해선 rebase를 해야 합니다.

 

Rebase라는 녀석을 열심히 설명하고 싶으나, 여기에서는 다른 좋은 자료로 대신하겠습니다. https://git-scm.com/book/ko/v1/Git-브랜치-Rebase하기 Rebase로는 여러 커밋을 합치는 등 여러 가지 일을 할 수 있습니다만, 여기에서의 주 목적은 브랜치가 갈라진 후에 master 브랜치에 생긴 변동사항을 develop 브랜치에 반영하는 것입니다. Rebase를 활용하면 브랜치들을 fast forward merge를 할 수 있는 상태로 만들 수 있습니다.

 

 

 

 

 

Merge가 항상 fast forward로 일어나게 되면, 결과적으로 모든 commit에 선후관계가 부여되게 되고, 일직선의 커밋 로그가 만들어집니다. 이렇게 생긴 커밋 로그는 복잡하게 꼬여 있지 않아서, 작업 내용의 흐름이 한눈에 들어오게 되고……. 보면 기분이 좋습니다. (발그레)

 

 

 

 

 

 

실제 작업 시 실수하지 않도록 주의해야 하는 부분들이 있습니다. Remote와 local의 브랜치 사본이 동기화되지 않아서 엉뚱한 커밋에 rebase를 한다거나, 아니면 rebase의 방향을 반대로(develop을 rebase하는 것이 아니라 master를 rebase)하여 대형사고를 일으킬 수도 있죠.

 

그래서 모든 팀원이 rebase를 자연스럽게 할 수 있을 때까지는 약간의 시간이 필요했습니다. 처음 몇 번의 rebase는 다 같이 모여서 했고, 그러다 뭔가 잘못 되면 다 같이 머리를 싸매고 고쳤죠. 이런 시간들도 팀웍의 일부가 되었다고 생각합니다.

 

 

3. 커밋 알림

 

 

9년의 게임 개발 경력을 가지고 계신 해줌의 최재현님(민지아빠)께서는 게임 개발에 이런 격언이 있다고 말씀해주셨습니다. “유저가 하는 모든 행동에는 피드백이 있어야한다.”

 

 

 

 

 

생각해보니, 내가 커밋을 했을 때 받을 수 있는 피드백이 제한적이라는 느낌이 듭니다. 확인하려면 굳이 명령어를 치거나, IDE의 VCS 탭을 들어가거나, GitHub에 접속해야하는 번거로움이 있습니다. 정보가 숨겨져 있는 셈이지요. 내가 커밋 메세지 몇 번 대충 쓴다 한들, 아무도 못 보고 지나칠 수 있습니다.

 

 

그래서 저희는 누군가 새로운 커밋을 등록하면 사내 메신저에 알림이 오도록 설정해두었습니다. 많은 업무용 메신저에서는 webhook을 이용하여 외부로부터 알림을 받을 수 있는 기능이 있습니다. 저희 팀의 소스코드는 GitHub에 있고, 사내 메신저로 사용하고 있는 Jandi에서는 클릭 몇 번만으로 메신저에 손쉽게 커밋 알림을 등록할 수 있습니다.

 

 

 

 

  • 메신저로 커밋 알림을 받는 것에는 많은 긍정적인 효과가 있습니다.
  • 자신이 작업을 했다는 것을 팀원들에게 공표하고 자랑하는 효과가 있습니다.
  • 커밋 메세지를 보다 성의있게 작성하게 됩니다. 이제 더 이상 커밋 메세지는 귀찮지만 채워넣어야 할 칸이 아니라 팀원에게 보내는 메세지가 됩니다.
  • 커밋을 작성하지 않은 사람도 팀원이 진행하고 있는 일에 대해서 인지하게 됩니다. 지금 내 코드를 업데이트(pull) 해야겠구나 하는 것을 알 수도 있고, 커밋 메세지를 보고 작업 내용에 대해 피드백을 줄 수도 있습니다.

 

 

그리고 이게 굉장히 사소하고 이상한 건데.. 내가 보낸 코드에 대해서 컴퓨터가 “알았다. 잘 받았어!”라고 해주는 느낌이 있습니다. 나중에는 push하고 나서 알림이 뜨는 것을 기다리는 스스로의 모습을 발견하게 됩니다.

 

 

4. 앞으로

 

 

저희는 의도적으로 pull request에 기반한 GitHub Flow (https://guides.github.com/introduction/flow/) 대신에 모든 구성원이 feature 브랜치에 바로 커밋을 추가할 수 있는 Git Flow (http://nvie.com/posts/a-successful-git-branching-model/) 모델로 작업했습니다. 팀이 작고 빠른 속도를 내야 했기 때문인데요, 바로 옆자리에서 일했기 때문에 굳이 pull request를 통하지 않아도 의사소통하거나 문제해결을 할 수 있다고 생각했습니다. 실제로도 어려운 문제에 봉착했을 때나 의사결정이 필요한 작업의 경우 짝 프로그래밍을 많이 하기도 했습니다. 다만 점차 시스템도 커지고 사람도 많아짐에 따라, 코드 리뷰를 자연스럽게 수행할 수 있게 되는 GitHub Flow 모델로 옮겨가려고 합니다.

 

 

Git의 커밋 메세지와 커밋 로그를 활용하는, 어찌보면 가장 기본적인 개발 협업 환경을 구축했던 이야기를 나누어 보았습니다. 기본일 수도 있지만 잘 실천하기가 생각보다 쉽지만은 않아서, 분명 어떤 분께는 도움이 되리라 믿고 공유하게 되었습니다. Git 뿐만 아니라 테스트 자동화, 배포 자동화 등 다른 개발 프로세스도 여러 시행착오를 거치며 정립을 하였는데, 다음 기회에 공유하도록 하겠습니다. (라고 말하고 기술블로그 턴을 마친다.)

 

 

팀으로 일할 땐, 한 사람만 잘 해서 되는 것이 아니라 모두가 다 같이 움직여야만 의미가 있는 일들이 많이 있습니다. 나 혼자 commit message 잘 써서는 의미가 없는 것처럼 말이지요. 이런 변화는 도입하기 힘들지만, 일단 한번 정착되면 경쟁자가 쉽게 따라올 수 없는 차별점이 됩니다. 이런 프로세스와 문화가 쌓여서 시너지를 낼 때 비로소 팀이 개인의 합 이상이 될 수 있다고 생각합니다. 커밋 메세지와 리베이스 가지고 한참 귀찮게 했던 저와 일하느라 고생하신 팀원들께 감사의 말씀을 드리면서 글을 마치도록 하겠습니다. 새해 복 많이 받으세요!

 


 

본 글은 해줌 IT 사업실 윤상웅님이 작성하신 글입니다.

[해줌피플] #2 해줌 머신러닝의 중심, 다재다능한 엔지니어 @윤상웅님


기업문화 엿볼 때, 더팀스

로그인

/