Git
Chapters ▾ 2nd Edition

6.3 GitHub - GitHub 프로젝트 관리하기

GitHub 프로젝트 관리하기

지금까지 남의 프로젝트에 기여하는 법을 살펴보았고 이번에는 직접 프로젝트를 운영하는 법을 살펴보자. 프로젝트를 생성해서 관리하는 방식 말이다.

새 저장소 만들기

저장소를 새로 만들고 프로젝트 코드를 공유해 보자. 대시보드 오른쪽에 있는 “New repository” 버튼을 클릭하면 저장소를 만드는 폼으로 이동한다. 맨 위 툴바의 사용자이름 옆에 있는 + 버튼을 클릭해도 된다.

``Your repositories'' 박스.
Figure 110. “Your repositories” 박스.
``new repository'' 메뉴.
Figure 111. 사용자이름 옆 “New repository” 메뉴.

위 버튼을 누르면 “새 저장소” 를 만드는 화면으로 이동한다.

``새 저장소'' 만들기.
Figure 112. “새 저장소” 만들기.

프로젝트 이름을 넣는 것만 필수다. 다른 것은 생략해도 된다. “Create Repository” 버튼을 클릭하면 '뿅’하고 <user>/<project_name> 위치에 GitHub 저장소가 생긴다.

아직 저장소에 코드가 하나도 없어서, GitHub는 Git 저장소를 만드는 방법이나 기존 Git 프로젝트를 넣는 방법을 보여준다. 이 내용을 다시 살펴보고 싶다면 Git의 기초를 보라. 여기서 또 설명하지 않는다.

GitHub에 프로젝트를 올렸으면 다른 사람들에게 프로젝트 URL을 알려주고 공유할 수 있다. 모든 프로젝트의 HTTPS URL은 `https://github.com/<user>/<project_name>`처럼 생겼고 SSH는 `git@github.com:<user>/<project_name>`처럼 생겼다. Git은 이 두 URL을 통해서 Fetch 하고 Push 할 수 있지만, 인증 방식은 사용하는 프로토콜에 따라 다르다.

Note

GitHub 계정 없이 Clone 할 수 있기 때문에 공개 프로젝트를 공유할 때는 SSH보다 HTTP URL를 더 많이 공유한다. SSH URL을 사용하려면 계정도 있어야 하고 SSH 키도 GitHub에 등록해야 한다. 브라우저에서 프로젝트 페이지에 접속할 때도 저장소 URL로 사용하는 HTTP URL을 그대로 사용한다.

동료 추가하기

저장소에 커밋 권한을 주고 싶은 동료가 있으면 “Collaborator” 로 추가해야 한다. Ben과 Jeff, Louise라는 동료가 있는데 그들이 내 저장소에 Push 할 수 있도록 하고 싶으면 내 프로젝트에 GitHub 계정들을 추가해야 한다. 계정이 추가된 사람은 해당 프로젝트와 Git 저장소에 “Push” 할 수 있을 뿐만 아니라 읽고 쓰기도 가능하다.

오른쪽 밑에 있는 ``Settings` ` 링크를 클릭한다.

저장소 설정 링크.
Figure 113. 저장소 설정 링크.

왼쪽 메뉴에서 “Collaborators” 를 선택한다. 텍스트 박스에 사용자이름을 입력하고 “Add collaborator” 를 클릭한다. 필요한 사람을 모두 추가할 때까지 반복한다. 그리고 오른쪽에 있는 “X” 를 클릭하면 권한이 회수된다.

저장소의 동료.
Figure 114. 저장소의 동료.

Pull Request 관리하기

프로젝트를 만들고 코드도 넣고 동료가 Push 할 수 있게 했다. 이제 Pull Reqeust가 왔을 때 어떻게 해야 하는지 보자.

Pull Request는 같은 저장소나 Fork 한 저장소에서 브랜치를 보내오는 것이다. 그 둘의 차이는 권한에 있다. Fork 한 저장소는 다른 사람의 저장소이기 때문에 그 보내온 브랜치에 Push 할 권한이 없다. 하지만, 같은 저장소의 브랜치에는 Push 할 수 있다.

“tonychacon” 이라는 사람이 “fade” 라는 Arduino 프로젝트를 만든 상황을 살펴보자.

이메일 알림

어떤 사람이 코드를 수정해서 Pull Request를 보내왔다. 그러면 새로운 Pull Request가 왔다는 메일이 담당자에게 간다. 새 Pull Request에 대한 이메일 알림. 같은 메일이 보내진다.

Pull Request 이메일 알림
Figure 115. 새 Pull Request에 대한 이메일 알림.

이 이메일은 무엇이 달라진 것인지 간략히 보여준다. 해당 Pull Request에서 어떤 파일이 얼마나 변경됐는지 보여준다. 그리고 Pull Request 페이지 링크도 있고 CLI로 Merge 하는 방법과 URL도 간략히 보여준다.

`git pull <url> patch-1`라는 명령이 궁금할 텐데 이렇게 하면 리모트 브랜치를 간단히 Merge 할 수 있다. 저장소를 리모트로 추가하지 않아도 된다. 필요하면 토픽 브랜치를 만들고 리모트 브랜치로부터 통합하기에서 배운 명령어로 Pull Request로 직접 Merge 해도 된다.

그리고 눈치챘을 테지만 .diff.patch URL은 Pull Request의 'Unified Diff’와 Patch 버전의 URL이다. 이 URL로 아래와 같이 Pull Request를 Merge 할 수 있다.

$ curl http://github.com/tonychacon/fade/pull/1.patch | git am

Pull Request로 함께 일하기

GitHub 플로우에서 설명했듯이 Pull Request를 만든 사람과 토론할 수 있다. GFM을 사용하여 특정 커밋을 선택하거나, 특정 라인을 지정하거나, 혹은 전체 Pull Request 자체에도 코멘트를 남길 수 있다.

일단 대화에 참여하고 나면 누군가 코멘트할 때마다 이메일 알림이 계속 온다. 그 이메일에는 Pull Request 페이지의 링크가 포함돼 있기 때문에 어떤 일이 일어나고 있는지 쉽게 알 수 있다. 그리고 답 메일을 보내면 Pull Request의 코멘트로 달린다.

답 메일
Figure 116. 답변 메일이 Pull Request의 스레드가 됨.

보내온 코드가 마음에 들어서 Merge 하고 싶다면 로컬에 가져와서 Merge 할 수 있다. git pull <url> <branch> 명령으로 Merge 하면 되는데 먼저 Fork 한 저장소를 리모트로 추가하고 Fetch 해서 Merge 한다.

GitHub 사이트에서 “Merge” 버튼을 누르는 것으로 간편하게 Merge 할 수 있다(Trivial Merge). “fast-forward” 가 가능할 때도 “non-fast-forward” Merge를 하기 때문에 Merge 커밋이 생긴다. 그래서 “Merge” 버튼을 클릭해서 Merge 하면 항상 Merge 커밋이 생긴다. 여기서 어떻게 해야 하는지 command line 힌트 링크를 클릭하면 Merge 버튼과 Pull Request를 수동으로 Merge 하기.과 같이 알려준다.

Merge 버튼
Figure 117. Merge 버튼과 Pull Request를 수동으로 Merge 하기.

만약 Pull Request를 Merge 하지 않기로 했다면 그냥 닫으면 된다. 그러면 그 Pull Request를 보낸 사람에게 알림이 간다.

Pull Request의 Ref

일일이 리모트를 등록하고 Pull 하는 것은 Pull Request를 많이 처리하는 사람에게는 고통스럽다. GitHub는 이럴 때 사용하는 방법을 제공한다. 이 내용은 Refspec에서 자세히 설명할 거고 조금 어려울 수 있다.

GitHub는 Pull Request의 브랜치를 서버에 있는 가상 브랜치로 노출해준다. GitHub가 자동으로 해주기 때문에 바로 이용하면 된다.

이걸 해보려면 저수준(“plumbing”) 명령어인 ls-remote 가 필요하다. 이 명령어는 아무래도 매일 쓰는 명령어는 아니지만, 서버에 어떤 Ref가 있는지 보여 준다. “plumbing” 명령어는 Plumbing 명령과 Porcelain 명령에서 자세히 설명한다.

이 명령어로 좀 전의 “blink” 저장소를 살펴보자. 저장소 브랜치뿐만 아니라 태그 등 온갖 Ref를 보여준다.

$ git ls-remote https://github.com/schacon/blink
10d539600d86723087810ec636870a504f4fee4d	HEAD
10d539600d86723087810ec636870a504f4fee4d	refs/heads/master
6a83107c62950be9453aac297bb0193fd743cd6e	refs/pull/1/head
afe83c2d1a70674c9505cc1d8b7d380d5e076ed3	refs/pull/1/merge
3c8d735ee16296c242be7a9742ebfbc2665adec1	refs/pull/2/head
15c9f4f80973a2758462ab2066b6ad9fe8dcf03d	refs/pull/2/merge
a5a7751a33b7e86c5e9bb07b26001bb17d775d1a	refs/pull/4/head
31a45fc257e8433c8d8804e3e848cf61c9d3166c	refs/pull/4/merge

저장소 안이라면 git ls-remote origin 이라고 실행시켜도 된다. 저장된 리모트 이름을 사용할 수 있다.

GitHub 저장소에 어떤 Pull Reqeust라도 열려있다면 refs/pull/ 로 시작하는 이름으로 Ref가 생성된다. 이것도 브랜치지만 refs/heads/ 로 시작하는 브랜치와는 달리 Clone과 Fetch 할 때 받아지지 않으며 기본적으로 무시된다.

Pull Request에는 두 종류의 Ref가 있다. /head 로 끝나는 것은 Pull Request 브랜치가 가리키는 마지막 커밋이다. 누군가 우리 저장소에 bug-fix 라는 브랜치를 Pull Request로 보내는 상황을 살펴보자. 이 브랜치는 a5a775 커밋을 가리킨다. bug-fix 브랜치는 Fork 한 저장소에 있는 브랜치라서 우리 저장소에 없다. 그럼에도 a5a775`를 가리키는 `pull/<pr#>/head 형식의 브랜치가 자동으로 생긴다. 그래서 매번 다른 저장소를 리모트로 등록하지 않고서도 Pull Request 브랜치를 쉽게 Pull 할 수 있다.

그 브랜치를 한번 가져와 보자.

$ git fetch origin refs/pull/958/head
From https://github.com/libgit2/libgit2
 * branch            refs/pull/958/head -> FETCH_HEAD

“리모트의 브랜치 originrefs/pull/958/head 로 Fetch 한다” 는 뜻이다. Git은 충실하게 전부 내려받고 마지막 커밋을 .git/FETCH_HEAD 에 저장한다. git merge FETCH_HEAD 으로 Merge 해서 테스트할 수 있다. 이렇게 Merge 하면 Merge 커밋 메시지가 약간 이상해진다. 또한 많은 Pull Request를 처리해야 하는 경우, 쓸데없는 Merge 커밋도 많아진다.

항상 Pull Request를 전부 가져오게 할 수 있다. .git/config 파일을 열어서 origin 리모트를 찾는다. origin 리모트는 사실 아래와 같은 것을 의미한다.

[remote "origin"]
    url = https://github.com/libgit2/libgit2
    fetch = +refs/heads/*:refs/remotes/origin/*

fetch = 로 시작하는 라인이 “refspec” 이라는 거다. 리모트 이름과 로컬 .git 디렉토리를 어떻게 매핑하는지 나타낸다. 여기서는 해당 리모트에서 refs/heads 에 해당하는 이름이 refs/remotes/origin 디렉토리에 매핑된다는 의미다. Refspec을 새로 추가해보자.

[remote "origin"]
    url = https://github.com/libgit2/libgit2.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

추가한 마지막 라인의 의미는 refs/pull/123/head 같은 Ref를 refs/remotes/origin/pr/123 에 저장'' 한다는 의미다. git fetch 라고 실행하면 새 Refspec의 브랜치도 가져온다.

$ git fetch
# …
 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
 * [new ref]         refs/pull/4/head -> origin/pr/4
# …

서버에 있는 모든 Pull Request을 추적하는 트래킹 브린치가 생겼다. 쓰기는 불가능하지만 계속 Fetch 해 올 수 있다. 이렇게 하면 Pull Request를 로컬에 가져와서 작업하는 게 편해진다.

$ git checkout pr/2
Checking out files: 100% (3769/3769), done.
Branch pr/2 set up to track remote branch pr/2 from origin.
Switched to a new branch 'pr/2'

head 로 끝나는 Refspec에 대해서 살펴봤고 이제 refs/pull/#/merge 처럼 생긴 Refspec을 알아보자. 이 브랜치는 GitHub에서 Merge 버튼으로 Merge 했을 때 적용되는 결과다. GitHub에서 실제로 Merge 하기 전에 로컬로 가져와서 먼저 테스트할 수 있다.

Pull Request 이어가기

Pull Request를 Merge 할 브랜치는 master 가 아니어도 된다. 주 브랜치를 고를 수도 있고 Pull Request를 열 때 다른 브랜치를 골라도 된다. 심지어 다른 Pull Request를 고를 수도 있다.

착착 잘 진행하는 어떤 Pull Request가 있는데 거기에 뭔가 아이디어를 더하고 싶다는 생각이 들었다. 좋은 아이디어라는 확신도 부족하고 무엇보다 Merge 될 브랜치에 Push 권한이 없다. 이럴 땐 Pull Request에 Pull Request를 보낼 수 있다.

Pull Request를 만들러 가면 페이지 위쪽에 어떤 저장소의 브랜치를 어떤 저장소의 브랜치로 요청하는 것인지를 보여주는 박스가 있다. “Edit” 버튼을 누르면 Fork 한 저장소 중 하나로 저장소를 변경하고 해당 저장소의 브랜치로 변경할 수 있다.

PR의 대상 브랜치
Figure 118. Pull Request을 어디로 보낼지 대상을 선택.

쉽게 다른 Fork 저장소나 Pull Request의 브랜치를 골라 Pull Request를 열 수 있다.

멘션과 알림

GitHub는 어떤 팀이나 사람에게 질문하거나 피드백을 받을 수 있도록 쉽고 편한 알림 시스템을 제공한다.

GitHub 어디에서나 `@`만 입력해도 동료나 기여자의 사용자이름이 자동완성 된다.

멘션
Figure 119. `@`만 입력.

자동완성 메뉴에 없는 사람도 입력할 수 있지만, 자동완성이 편하고 빠르다.

GitHub에서 글을 쓸 때 `@멘션`을 하면 해당 사용자에게 알림이 간다. 일일이 의견을 물으러 다니는 것보다 이렇게 토론에 참여시키는 게 훨씬 유용하다. GitHub에서는 멘션으로 팀의 동료나 다른 사람을 이슈나 Pull Request에 참여시킨다.

한번 `@멘션`으로 언급되면 그 사람은 “구독 상태(Subscribed)” 가 된다. 그래서 해당 이슈나 Pull Request에서 계속 알림이 온다. 이슈나 Pull Request를 직접 만들었거나, 해당 저장소를 'Watching’하는 상태이거나, 코멘트를 단 경우에도 구독 상태가 된다. 더는 알림을 받고 싶지 않으면 화면의 “Unsubscribe” 버튼으로 멈출 수 있다.

Unsubscribe
Figure 120. 특정 이슈와 Pull Request의 알림 끊기(Unsubscribe).

알림 페이지

GitHub의 “알림” 은 프로젝트에서 어떤 일이 일어나면 바로 알 수 있도록 안내해 주는 것이다. 이 알림은 원하는 방법으로 설정해 쓸 수 있다. 설정의 “Notification center” 탭에 가면 설정할 수 있는 옵션이 있다.

Notification center
Figure 121. Notification center 옵션.

알림을 이메일로 받을지 웹으로 받을지 선택할 수 있다. 물론 두 가지 방법을 동시에 사용해도 된다. 그리고 그냥 대화에 참여하는 경우와 프로젝트를 Watching 하는 경우를 나누어 선택할 수 있다.

웹 알림

웹 알림은 GitHub에서 제공하는 것으로 GitHub 사이트에서만 확인할 수 있다. 이 옵션을 선택하면 알림이 오면 알림 아이콘에 파란 점을 볼 수 있다. Notification center.을 확인해보자.

Notification center
Figure 122. Notification center.

알림 아이콘을 클릭하면 알림 메시지를 확인할 수 있다. 알림은 프로젝트별로 분류된다. 왼쪽 메뉴에 있는 프로젝트를 선택하면 관련 알림만 걸러서 볼 수 있다. 각 알림에 있는 체크박스를 클릭해서 읽었다고 표시를 할 수 있고 제일 위에 있는 체크박스를 클릭하면 해당 알림에 대해서 전부 읽음 표시를 할 수 있다. 그리고 Mute 버튼을 클릭하면 해당 사항에 대해서는 더는 알림이 오지 않는다.

이 기능을 사용하면 쏟아지는 알림들도 매우 효율적으로 처리할 수 있다. GitHub의 파워 유저는 이메일 알림을 꺼놓고 GitHub 사이트에서만 알림을 관리하기도 한다.

이메일 알림

이메일 알림을 켜 놓으면 이메일로도 GitHub 알림을 확인할 수 있다. 이메일 알림으로 온 코멘트새 Pull Request에 대한 이메일 알림.의 예를 보면 관련 알림들이 이메일 스레드로 잘 분류되는 것을 볼 수 있다. 그래서 이메일 스레드를 잘 지원하는 메일 클라이언트를 사용하는 것이 좋다.

GitHub가 보낸 이메일 헤더를 보면 여러 가지 메타데이터가 들어 있다. 그래서 사용자는 이메일 필터나 룰 같은 자동 관리 기능으로 쉽게 관리할 수 있다.

새 Pull Request에 대한 이메일 알림.에서 보여준 이메일의 헤더는 아래와 같다.

To: tonychacon/fade <fade@noreply.github.com>
Message-ID: <tonychacon/fade/pull/1@github.com>
Subject: [fade] Wait longer to see the dimming effect better (#1)
X-GitHub-Recipient: tonychacon
List-ID: tonychacon/fade <fade.tonychacon.github.com>
List-Archive: https://github.com/tonychacon/fade
List-Post: <mailto:reply+i-4XXX@reply.github.com>
List-Unsubscribe: <mailto:unsub+i-XXX@reply.github.com>,...
X-GitHub-Recipient-Address: tchacon@example.com

프로젝트에 따라 혹은 Pull Request인지에 따라 분류하거나 다른 주소로 재전송하고 싶다면 Message-ID 를 이용하는 게 좋다. 이 데이터는 <user>/<project>/<type>/<id> 형식으로 돼 있다. 만약 이슈에 대한 데이터면 `<type>`부분이 “pull” 이 아니라 “issues” 라고 돼 있을 것이다.

List-PostList-Unsubscribe 필드를 인식하는 메일 클라이언트를 사용하고 있으면 좀 더 편리하게 사용할 수 있다. List-Post 는 이메일로 리스트에 글을 올리는 데 사용하고 List-Unsubscribe 는 이메일 클라이언트에서 알림을 그만 받도록 할 수 있다. 이슈와 Pull Request페이지의 “Unsubscribe” 버튼을 클릭하거나 웹 알림 페이지에서 “Mute” 버튼을 클릭하는 것과 같다.

이메일과 웹 알림이 둘 다 켜져 있으면 알림이 이메일로도 오고 웹으로도 온다. 이메일 클라이언트에서 이미지가 허용되어 있으면, 메일을 읽었을 때 웹에서도 읽었다고 표시된다.

특별한 파일

저장소에 있는 파일 중에서 GitHub가 사용하는 몇 가지 특이한 파일들이 있다.

README

GitHub는 저장소 랜딩 페이지를 보여줄 때 README 파일을 이용해서 보여준다. README 파일 형식에 상관없이 잘 보여준다. README 파일이든 README.md 파일이든 README.asciidoc 파일이든 GitHub가 자동으로 렌더링해서 보여준다.

많은 사람이 이 파일에 저장소나 프로젝트에 처음 방문한 사람들에게 필요한 정보를 정리해 둔다. 보통 아래와 같은 내용을 쓴다.

  • 무슨 프로젝트인지

  • 설정하고 설치하는 방법

  • 사용법과 실행 결과에 대한 예제

  • 프로젝트의 라이센스

  • 기여하는 방법

GitHub는 README 파일을 렌더링하는 것이기 때문에 이미지나 외부 링크를 적어도 된다.

CONTRIBUTING

GitHub는 CONTRIBUTING 파일도 인식한다. README와 마찬가지로 원하는 파일 형식을 사용하면 된다. Pull Request를 열 때 이 파일이 있으면 CONTRIBUTING 파일이 있음을 보여준다.과 같이 링크를 보여준다.

Contributing notice
Figure 123. CONTRIBUTING 파일이 있음을 보여준다.

이 파일에는 프로젝트에 기여하는 방법과 Pull Request 규칙 같은 것을 적는다. 그러면 사람들이 Pull Request를 열 때 이 가이드라인을 참고할 수 있다.

프로젝트 관리

특별히 관리할 만한 게 별로 없지만 알고 있으면 유용한 것들을 소개한다.

기본 브랜치 변경하기

기본 브랜치를 “master” 말고 다른 브랜치로 설정할 수 있다. Pull Request를 열 때 설정한 기본 브랜치가 기본으로 선택된다. 기본 브랜치는 저장소 설정 페이지의 “Options” 탭에서 변경한다.

기본 브랜치
Figure 124. 기본 브랜치 변경하기.

기본 브랜치 변경은 쉽고 정말로 기본으로 쓰인다. 저장소를 Clone 하면 여기서 설정한 브랜치가 기본으로 Checkout된다.

프로젝트 넘기기

프로젝트 소유자를 다른 사용자나 Organization으로 변경할 수 있다. 저장소 설정 페이지의 “Options” 탭을 보면 페이지 아래쪽에 “Transfer ownership” 항목이 있다. 여기 있는 Transfer 버튼으로 프로젝트를 넘길 수 있다.

프로젝트 넘기기
Figure 125. 다른 GitHub 사용자나 Organization에 프로젝트 넘기기.

맡던 프로젝트를 다른 사람에게 넘겨주거나 프로젝트가 커져서 Organizaiton 계정으로 옮기고 싶을 때 유용하다.

저장소만 옮겨지는 것이 아니라 'Watching’하는 사람이나 'Star’한 사람까지도 함께 옮겨진다. 그리고 URL은 Redirect되는데 웹 접속뿐만 아니라 Clone 이나 Fetch 요청까지도 Redirect된다.