작년 겨울부터 오픈소스에 관심이 생겨 이곳저곳에 이슈도 올리고 풀 리퀘스트도 보내고 있다. 오픈소스 기여의 가장 큰 장점은 남의 코드를 많이 읽을 수 있다는 점과 기술 트렌드를 계속 확인할 수 있다는 점이다. 그리고 영작 실력도 미세하게 (...) 향상된 것 같다. 처음 오픈소스 활동을 시작할 때 네이버 오픈소스 가이드가 큰 도움이 됐다. 오픈소스에 대한 감은 잡히지만 생각보다 구체적인 내용을 다루진 않는다.

Git이 설치되어 있지 않다면 설치하고, GitHub에 가입되어 있지 않다면 가입하도록 하자. 만약 익숙치 않다면 깃허브 사용법 또는 누구나 쉽게 이해할 수 있는 Git 입문을 얕게라도 읽어보는 것을 추천한다. 깃허브말고 GitLab이나 BitBucket도 있는데, 역시 깃허브의 규모가 가장 크다.

간단하게 오픈소스 컨트리뷰션과 관련된 용어를 정리하면 이렇다:

  • Repository: 코드나 문서를 비롯한 리소스를 저장하는 곳을 말하며, 프로젝트 단위로 만든다. 원격 저장소(Remote repository)는 깃허브같은 호스팅 서비스 서버에 올라가 있는 저장소를 말하고, 로컬 저장소(Local repository)는 개인 컴퓨터에 있는 저장소를 말한다. 그냥 리포(repo)라고 줄여쓰기도 한다.
  • Fork: 다른 사람의 원격 저장소를 그대로 복사해 내 계정의 원격 저장소로 만드는 것을 의미한다.
  • Pull Request: 내 저장소의 변경 내용을 다른 사람의 저장소에 반영하도록 요청하는 것. 풀 리퀘스트를 보내면 해당 저장소의 메인테이너(프로젝트를 관리하는 사람)이 내 작업을 반영할지 말지 결정한다. 풀 리퀘, PR이라고 줄여말한다.
  • Issue: 프로젝트의 버그 리포트, 기능 제안, 질문 등을 말하며, 깃허브 저장소에서 Issues 탭에 들어가면 다양한 토론을 볼 수 있다.

🔭 프로젝트 고르기

처음 오픈소스 생태계에 들어서면 일단 혼란스럽다. 첫 번째 난관은 '어떤 프로젝트에 컨트리뷰션할 것인가?'인데, 가장 좋은 것은 자신이 사용하고 있는 프로젝트에 컨트리뷰션하는 것이다. 딱히 사용중인 오픈소스가 없고, 일단 컨트리뷰션을 해보고 싶다면 깃허브의 Explore 탭이나 CodeTriage를 둘러보면 자신이 다룰 수 있는 언어와 환경에 맞는 프로젝트를 찾을 수 있다. 재밌는 프로젝트들이 많다.

꼭 중대한 버그를 고치거나 기능을 개선, 추가하려 하지 않아도 된다. 실제로 전체 컨트리뷰션 비율 중 코드를 수정하는 것보다 문서의 오타를 고치거나 번역하는 컨트리뷰션의 비율이 더 높다. 뿐만 아니라 디자인 작업이나 의견 제시도 컨트리뷰션이니까 코드 수정에 압박받을 필요는 없다.

뭔가 컨트리뷰션할만한 프로젝트를 찾았다면 먼저 이슈 탭에 들어가 내가 하려는 작업을 이미 누군가하고 있지 않은지 확인해본다. 검색 결과가 따로 없고, 하려는 작업이 프로젝트의 방향이나 구조에 큰 영향을 끼치지 않는다면 바로 수정 작업에 들어가도 된다. 그것이 아니라면 직접 이슈를 올려서 의견을 받아보는 것이 좋다. 프로젝트마다 컨트리뷰션 가이드를 마련해두고 있으니 확인하길 권한다.

📌 저장소 포크하기

컨트리뷰션을 하려면 프로젝트의 저장소를 포크(Fork)해서 내 깃허브 계정에 동일한 저장소를 만들어야 한다. 만약 프로젝트의 원본 저장소를 아무나 수정할 수 있다면 헬게이트가 열릴 것이 뻔하기 때문에...

나는 TUI Editor라는 프로젝트에 컨트리뷰션을 하려 한다. 맨 오른쪽 'Fork' 버튼을 누르면 자동으로 저장소가 복사된다. 만약 파일이 많고 용량이 크다면 포크하는 데 시간이 조금 걸릴 수 있다. 위 메뉴에 대해 좀 사족을 달자면, 'Watch'는 저장소에서 일어나는 활동에 대한 알림을 받을 것인지 설정하는 것이고, 'Star'는 저장소를 북마크하는 것이다. 스타는 단순히 북마크 기능을 하지만, 프로젝트를 응원한다는 의미가 될 수도 있으며, 프로젝트의 완성도와 인기의 척도(!)이기도 하다.

💾 저장소 클론하기

저장소를 클론(Clone)한다는 것은 원격 저장소를 그대로 복제해 로컬 저장소로 가져오겠다는 것이다. 즉, 깃허브에 있는 저장소를 다운받아서 내 컴퓨터에 저장한다는 의미다.

먼저 'Clone or download' 버튼을 눌러서 나오는 주소를 복사한다. 그리고 컴퓨터에서 터미널을 열어서 clone 명령을 입력해주면 된다.

$ git clone https://github.com/nhnent/tui.editor.git

그러면 원격 저장소의 모든 파일이 담긴 폴더가 만들어진다.

🚧 작업하기

이제 내용을 수정한다. 코드를 고쳐도 좋고, 문서를 수정해도 된다. 작업 공간은 로컬 저장소니까 마음대로 하자!

📤 추가/커밋/푸시하기

변경 내용의 반영에는 3단계를 거치게 된다. 먼저 1단계 추가(Add)는 변경한 내용을 스테이징 영역(Staging area)에 올리는 것을 말하며, 2단계 커밋(Commit)은 스테이징 영역에 있는 내용을 최종 확정하겠다는 의미다.

$ git add *
$ git commit -m "Update README.md"

커밋할 때는 변경 내용에 관한 메시지를 달 수 있다. 메시지는 이후 버전 관리를 편리하게 해주며, 다른 사람들에게 내가 어떤 내용을 변경했는지 요약해서 보여줄 수 있다. 다시말해 잘 써야 된다는 것이다. 좋은 git 커밋 메시지를 작성하기 위한 7가지 약속을 읽어보길 권한다. 커밋까지는 아직 원격저장소에 변경 내용이 반영되지 않은 상태다. 마지막 3단계로 푸시(push)를 해야 한다.

$ git push origin master

이제 내 원격 저장소에 변경 사항이 반영됐다. 하지만 원본 저장소에는 아직 내용이 반영되지 않았다. 여기까지는 아직 컨트리뷰션을 한 것이 아니다.

📮 풀 리퀘스트 보내기

풀 리퀘스트(Pull request)는 원본 저장소에 내 변경 내용을 반영해 달라고 요청하는 것이다. 풀 리퀘스트를 보내면 프로젝트를 관리하는 메인테이너(Maintainer)들이 작업 내용을 검토하고, 프로젝트에 반영할지 안 할지 결정한다.

'Pull requests' 탭에서 'New pull request' 버튼을 누른다.

바로 나타나는 것은 브랜치 사이의 변경 내용에 관한 풀 리퀘를 보내는 것이다. 나는 저장소를 포크해서 작업했으니까 위에 있는 'compare across forks' 링크를 눌러 저장소 사이의 변경 내용에 관한 풀 리퀘를 보내도록 해준다. 우측의 'head fork'에서 내가 포크해서 작업한 리포를 선택하면 된다.

그렇게 하면 글을 쓰는 에디터가 나온다. 제목은 변경 내용에 대한 요약을 쓰거나 그냥 커밋 메시지를 그대로 쓰기도 한다. 바로 이해할 수 있는 작업이었다면 따로 설명을 쓰지 않아도 되고, 변경 내용이 복잡하다면 설명을 쓴다. 만약 내가 작업한 내용에 관한 기존 이슈가 등록되어 있다면 #1713처럼 # 뒤에 이슈 번호를 적어 참조를 달아준다.

이 단계에서 가장 큰 문제는 왠지모를 불안함이었다. 풀 리퀘스트를 보내면 메인테이너들에게 알림이 가고, 내 컨트리뷰션은 완전히 공개된다. 일단 내 코드를 누군가에게 보여주는 것이 가장 떨린다. 그리고 내 컨트리뷰션에 부정적인 리뷰가 올 것 같아서 불안하기도 하다. 그래도 일단 보내는 것이다. (특별한 사정이 있는 프로젝트가 아니라면) 컨트리뷰션 자체를 싫어하는 사람은 없다.

😴 기다리기

풀 리퀘스트를 날리고나면 메인테이너가 내용을 확인하고 병합(Merge)해주길 기다린다. 며칠이 지나도 답이 없을 수 있다. 그렇다고 메인테이너를 재촉하지는 말자. 오픈소스 컨트리뷰터들은 보람을 먹고 사는 사람들이고, 각자의 본업이 따로 있는 경우가 대부분이다. 그냥 기다리는 것이다. 만약 내 요청이 묻힌 것 같다면 @ParkSB처럼 댓글로 태그해 정중하게 리뷰를 요청해볼 수 있다.

위 사진은 Hyper라는 프로젝트에 풀 리퀘스트를 보내고 반영된 것이다. #2579로 2579번 이슈에 참조를 달았고, 병합 후 메인테이너가 풀 리퀘를 닫았다.

슬프지만 내 작업이 거절될 수도 있다. 너무 상처받지 말고 다른 할 일을 찾아보자 (...) 왜 반영할 수 없는지 친절하게 설명해주는 메인테이너가 있는 반면, 말도 없이 풀 리퀘를 닫아버리는 메인테이너도 있다. 네이버 오픈소스 세미나에 가서 들었던 Outsider님의 강연에 따르면 이슈나 풀 리퀘에 달린 라벨을 보고 대략 메인테이너들의 성향을 대략 짐작할 수 있다고 한다.

이렇게 라벨이 많이 달려 있는 프로젝트의 메인테이너들은 친절하다고....

📥 저장소를 최신으로 유지하기

만약 같은 프로젝트에 앞으로 계속 컨트리뷰션을 하고 싶다면 해당 원격 저장소의 업데이트된 내용을 지속적으로 받아볼 수 있어야 한다. 물론 쉬운 방법이 있다. TUI Editor에 컨트리뷰션하는 경우 터미널을 열고 아래와 같은 명령어를 입력한다.

$ git remote add upstream https://github.com/nhnent/tui.editor.git

원본 저장소를 업스트림(Upstream)이라고 하며, 위 명령을 실행하면 upstream이라는 이름으로 원격 저장소가 추가된다. 업데이트된 원본 저장소의 내용을 가져오려면 아래 명령을 입력한다.

$ git fetch upstream
$ git checkout master
$ git merge upstream/master

fetch로 upstream 저장소의 내용을 가져와서 merge 명령으로 upstream 저장소의 master 브랜치 내용을 내 로컬 저장소에 병합한다. 이렇게 한 번씩 fetchmerge를 해주면 로컬 저장소를 최신으로 유지할 수 있다.