Pro git - 6.2
Updated:
Pro git - GitHub 프로젝트에 기여하기
1. 프로젝트 Fork 하기
- “Fork” 하면 GitHub이 프로젝트를 통째로 복사해준다.
- 그 복사본은 사용자 네임스페이스에 있고 Push 할 수도 있다.
- 이 방식에서는 사람들을 프로젝트에 추가하고 Push 권한을 줘야 할 필요가 없다.
- 사람들은 프로젝트를 “Fork” 해서 Push 한다.
- 그리고 Push 한 변경 내용을 원래 저장소로 보내 기여한다.
- 이것을 Pull Request라고 부른다.
- 토론 스레드를 만들고 거기서 코드 리뷰를 하면서 토론하는 스레드를 만들어 토론을 시작한다.
- 프로젝트 소유자 마음에 들 때까지 소유자와 기여자는 함께 토론한다. 마음에 들게 되면 Merge 한다.
2. GitHub 플로우
- GitHub은 Pull Request가 중심인 협업 워크플로를 위주로 설계됐다.
- 이 워크플로는 Fork 해서 프로젝트에 기여하는 것인데 단일 저장소만 사용하는 작은 팀이나 전 세계에서 흩어져서 일하는 회사, 혹은 한 번도 본 적 없는 사람들 사이에서도 유용하다.
- Git 브랜치에서 설명했던 토픽 브랜치 중심으로 일하는 방식이다.
2.1 flow
- 프로젝트를
Fork
한다. master
기반으로 토픽 브랜치를 만든다.- 뭔가 수정해서 커밋한다.
- 자신의 GitHub 프로젝트에 브랜치를 Push 한다.
- GitHub에 Pull Request를 생성한다.
- 토론하면서 그에 따라 계속 커밋한다.
- 프로젝트 소유자는 Pull Request를 Merge 하고 닫는다.
- 이 방식은 기본적으로 Integration-Manager 워크플로에서 설명하는 Integration-Manager 워크플로와 같다.
- 토론이나 리뷰를 이메일이 아니라 GitHub에서 제공하는 웹 기반 도구를 사용하는 것뿐이다.
2.2 Pull Request 만들기
- Tony는 GitHub에 있는 https://github.com/schacon/blink에서 프로그램을 찾았다.
- 프로그램을 수정하고 원 프로젝트에 다시 보내기로 했다.
- Fork 버튼을 클릭해서 프로젝트를 복사한다.
- 사용자 이름이 “tonychacon” 이라면
https://github.com/tonychacon/blink
에 프로젝트가 복사된다. - 이 프로젝트는 본인 프로젝트이고 수정할 수 있다.
- 이 프로젝트를 로컬에 Clone 해서 토픽 브랜치를 만들고 코드를 수정하고 나서 GitHub에 다시 Push 한다.
$ git clone https://github.com/tonychacon/blink (1)
Cloning into 'blink'...
$ cd blink
$ git checkout -b slow-blink (2)
Switched to a new branch 'slow-blink'
$ sed -i '' 's/1000/3000/' blink.ino (macOS) (3)
# If you're on a Linux system, do this instead:
# $ sed -i 's/1000/3000/' blink.ino (3)
$ git diff --word-diff (4)
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
[-delay(1000);-]{+delay(3000);+} // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
[-delay(1000);-]{+delay(3000);+} // wait for a second
}
$ git commit -a -m 'three seconds is better' (5)
[slow-blink 5ca509d] three seconds is better
1 file changed, 2 insertions(+), 2 deletions(-)
$ git push origin slow-blink (6)
Username for 'https://github.com': tonychacon
Password for 'https://tonychacon@github.com':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.b
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
* [new branch] slow-blink -> slow-blink
- Fork 한 개인 저장소를 로컬에 Clone 한다.
- 무슨 일인지 설명이 되는 이름의 토픽 브랜치를 만든다.
- 코드를 수정한다.
- 잘 고쳤는지 확인한다.
- 토픽 브랜치에 커밋한다.
- GitHub의 개인 저장소에 토픽 브랜치를 Push 한다.
- Fork 한 내 저장소에 가면 GitHub은 토픽 브랜치가 하나 Push 됐다는 것을 알려주고 원 저장소에 Pull Request를 보낼 수 있는 큰 녹색 버튼을 보여준다.
- 아니면 저장소의 브랜치 페이지로(
https://github.com/<user>/<project>/branches
) 가서 해당 브랜치의 “New pull request” 버튼을 이용한다. - 녹색 버튼을 클릭하면 Pull Request의 제목과 설명을 입력하는 화면이 보인다.
- 항샹 프로젝트 소유자가 판단을 내릴 수 있을 정도로 공을 들여 작성해야 한다.
-
왜 수정했는지 얼마나 가치 있는지 설명해서 관리자를 설득해야 한다.
- 그리고 “ahead” 토픽 브랜치가
master
브랜치에서 달라진 커밋도 보여주고 수정된 내용을 “unified diff” 형식으로 보여준다. - 이 수정 내용이 프로젝트 관리자가 Merge 할 내용이다.
- 화면에 있는 Create pull request 버튼을 클릭하면 프로젝트 원소유자는 누군가 코드를 보냈다는 알림을 받는다.
- 그 알림에는 해당 Pull Request에 대한 모든 것을 보여주는 페이지의 링크가 들어 있다.
2.3 Pull Request 놓고 감 놓고 배 놓기
-
Pull Request가 오면 프로젝트 소유자는 변경 점이 무엇인지 확인한 후, Merge 혹은 거절하거나 코멘트를 달 수 있다.
- 프로젝트 소유자는 unified diff 형식의 변경사항을 검토하고 즉각 해당 라인에 코멘트를 달 수 있다.
- 관리자가 코멘트를 달면 Pull Request를 만든 사람에게 알림이 간다.
- 실제로는 저장소를 ‘Watch’하는 사람 모두에게 알림이 간다.
- 누구나 Pull Request에 코멘트를 달 수 있다.
- GitHub에서는 해당 토픽 브랜치에 이어서 커밋하고 Push 하면 된다.
- 최종 Pull Request에서 Push로 업데이트한 PR의 코드를 보면 예전 코드에 달렸던 코멘트는 나오지 않는다.
- 추가된 커밋으로 인해 코드가 수정되었기 때문이다.
- 기존 PR에 이어서 Push를 하면 알림이 가지 않는다.
- Pull Request의 “Files Changed” 탭을 클릭하면 “unified” diff를 볼 수 있다.
- 이 Pull Request가 주 브랜치에 Merge 되면 어떻게 달라지는지 보여준다.
git diff
명령을 빌어 표현하자면git diff master…<branch>
와 같은 명령이 실행되는 거고<branch>
는 Pull Request의 브랜치를 의미한다.- GitHub은 Pull Request가 Merge 될 수 있는지 검사해서 서버에서 Merge 할 수 있도록 Merge 버튼을 제공한다.
- 이 버튼은 저장소에 쓰기 권한이 있는 사람만 볼 수 있고 이 버튼으로 Merge 하면 Merge 커밋이 생긴다(Trivial Merge).
- “fast-forward” Merge가 가능할 때도 “non-fast-forwrd” 로 Merge 한다.
- 로컬에 Pull Request 브랜치를 당겨와서 Merge 해도 된다.
master
브랜치에 Merge 해서 GitHub에 Push 하면 자동으로 해당 Pull Request가 닫힌다.
3. Pull Request 팁
3.1 Patch를 Pull Request로 보내기
- 보통 프로젝트에서는 Pull Request의 Patch가 완벽하고 큐처럼 꼭 순서대로 적용돼야 한다고 생각하지 않는다.
- 메일링 리스트를 사용하던 프로젝트에서는 Patch 순서가 의미가 있다고 생각한다.
- GitHub의 Pull Request는 어떤 주제를 두고 논의하는 자리다. 논의가 다 무르익으면 Merge 한다.
- 일반적으로 처음부터 완벽한 코드를 보낼 수 없어서 메일링 리스트로 Patch를 보낼 일은 별로 없다.
- Pull Request는 초기부터 프로젝트 관리자와 소통할 수 있도록 해주기 때문에 혼자 답을 찾는 게 아니라 커뮤니티에서 함께 찾을 수 있다.
- 누군가 Pull Request를 열면 관리자와 커뮤니티는 어떻게 수정하는 게 좋을지 의견을 낸다.
- Patch를 처음부터 다시 전체로 작성하지 않아도 된다.
- 수정한 만큼만 해당 브랜치에 커밋하고 하던 일과 대화를 계속 해 나가면 된다.
- 최종 Pull Request로 돌아가서 다시 보면 기여자가 커밋을 Rebase 하거나 Pull Request를 다시 열지 않았다는 것을 확인할 수 있다.
- 그냥 기존 브랜치에 좀 더 커밋하고 Push 했을 뿐이다.
- 나중에 시간이 지나서 이 Pull Request를 다시 읽으면 왜 이런 방향으로 결정했는지에 대한 맥락을 쉽게 알 수 있다.
- 웹사이트에서 “Merge” 버튼을 누르면 Merge 커밋을 일부러 남기겠다는 뜻이 된다.
- 이 Merge 커밋에는 Pull Request 정보가 들어가기 때문에 필요하면 언제든지 맥락을 확인할 수 있다.
3.2 Pull Request를 최신으로 업데이트하기
- Pull Request가 만든 지 오래됐거나 깨끗하게 Merge 되지 않으면 메인테이너가 쉽게 Merge 할 수 있게 수정한다.
-
GitHub은 자동으로 Merge 할 수 있는 Pull Request인지 아닌지 Pull Request 페이지 하단에서 알려준다.
- 깨끗하게 Merge 할 수 없는 Pull Request 같은 메시지를 보면 해당 브랜치를 고쳐서 녹색으로 만든다. 메인테이너가 고치지 않아도 되도록 한다.
- 이 문제를 해결하는 방법은 두 가지가 있다.
- 대상 브랜치(보통은
master
브랜치)를 기준으로 Rebase 하는 방법이 있고 대상 브랜치를 Pull Request 브랜치에 Merge 하는 방법이 있다. - GitHub을 사용하는 개발자는 대부분 후자를 고른다. 앞서 살펴봤던 것과 같은 이유다. Rebase 하면 히스토리는 깨끗해지지만 훨씬 더 어렵고 에러 나기 쉽다.
- Pull Request가 Merge 될 수 있도록 대상 브랜치를 Merge 하려면 먼저 원 저장소를 리모트로 추가한다.
- 그리고 나서 Fetch 하고 그 저장소의 대상 브랜치를 해당 토픽 브랜치에 Merge 한다.
- 문제를 해결하고 그 브랜치에 도로 Push 한다.
- “tonychacon” 예제에 이 워크플로를 적용해보자. 원저자가 뭔가 수정을 했는데 Pull Request와 충돌이 난다. 여기부터 살펴보자.
$ git remote add upstream https://github.com/schacon/blink (1)
$ git fetch upstream (2)
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
* [new branch] master -> upstream/master
$ git merge upstream/master (3)
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.
$ vim blink.ino (4)
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
into slower-blink
$ git push origin slow-blink (5)
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
ef4725c..3c8d735 slower-blink -> slow-blink
- 원 저장소를 “upstream” 이라는 이름의 리모트로 추가한다
- 리모트에서 최신 데이터를 Fetch 한다
- 대상 브랜치를 토픽 브랜치에 Merge 한다
- 충돌을 해결한다
- 동일한 토픽 브랜치에 도로 Push 한다
-
이렇게 하면 Pull Request는 자동으로 업데이트되고 깨끗하게 Merge 할 수 있는지 재확인된다.
- 연속성은 Git의 장기 중 하나다.
- 오랫동안 무엇인가 만들고 있다면 최신으로 유지하기 위해 대상 브랜치를 쉽게 Merge 해 올 수 있다.
- 다 마칠 때까지 하고 또 하고 할 수 있다.
- Merge 할 때 발생하는 충돌만 해결하면 되고 지속적으로 개발 프로세스를 관리할 수 있다.
- 브랜치를 꼭 깨끗하게 유지하고 싶어서 Rebase 해야 한다고 생각한다면 이미 열어 놓은 Pull Request에 대고 Push 하지 말아야 한다.
- 그럼 이 브랜치를 가져다 Merge 해 놓은 사람들은 Rebase 의 위험성에 설명했듯이 충격에 빠질 것이다.
- 대신 브랜치를 새로 만들어 Push 한다.
- 그리고 Pull Request도 새로 여는데 원 Pull Request가 뭔지 알 수 있도록 참조를 달고 원래 것은 닫는다.
3.3 참조
- 그럼 바로 “어떻게 Pull Request를 참조시키지?” 라는 의문이 들겠지만, 방법은 매우 많다.
- GitHub에 쓰기 가능한 곳 어디에서나 참조를 달 수 있다.
- 먼저 Issue와 Pull Request를 서로 참조시키는 방법부터 살펴보자.
- 모든 Pull Request와 Issue에는 프로젝트 내에서 유일한 번호를 하나 할당한다.
- 예를 들어, 3인 Pull Request와 #3인 Issue는 동시에 있을 수 없다.
<num>
과 같은 형태로 코멘트가나 설명에 Pull Request와 Issue를 참조시킬 수 있다.- 이 방법은 단일 프로젝트 범위에서만 유효하다.
- Fork 저장소의 Issue나 Pull Request를 참조시키려고 한다면
username#<num>
라고 쓰고 아예 다른 저장소면username/repo#<num>
라고 써야 한다. - 설명을 위해 이미 브랜치를 Rebase 했고 Pull Request를 새로 만들었다고 하자.
- 그럼 예전 Pull Request가 뭔지 알 수 있도록 새것에서 예전 것을 참조하게 해보고 Pull Request의 상호 참조 편집같이 Fork 한 저장소의 이슈나 아예 다른 저장소의 이슈도 참조하게 해보자.
4. GitHub Flavored Markdown
- “GitHub Flavored Markdown” 이라는 형식으로 이슈나 Pull Request의 설명, 코멘트, 코드 주석 등에서 글을 쓸 수 있다.
- Markdown 형식으로 글을 쓰면 그냥 텍스트로 쓴 글이지만 형식을 갖춰 미끈하고 아름답게 렌더링된다.
4.1 GitHub Flavored Markdown
- GitHub Flavored Markdown(이하 GFM)은 기본 Markdown을 확장했다.
- GFM은 Pull Request나 이슈 등의 글을 쓸 때 매우 유용하다.
4.2 이모티콘
- 넣을 수 있다.
4.3 이미지
- 넣을 수 있다.