초심자를 위한 Github 협업 튜토리얼 (with 토끼와 거북이)

시작하기 전에…

팀 개발을 위한 Git, GitHub 시작하기

팀 개발을 위한 Git, GitHub 시작하기

정호영, 진유림

개발자, 디자이너, 기획자 다함께 깃·깃허브 입문이 책은 시나리오를 곁들인 실습으로 시작해서 깃과 깃허브를 처음 접하는 사람 또는 좀 더 깊은 난이도에서 깃과 깃허브를 다루고 싶은 개발자, 디자이너, 기획자 모두에게 유용하다. 챕터 0장에서 1시간이면 깃·깃허브의 기본 사용법을 따라할 수 있도록 구성했…

토끼와 거북이 대신 고양이와 문어, 그리고 너구리가 등장하는 저의 Git & GitHub 책이 나왔습니다 ^.^ 블로그 독자분들이 사랑해주신 덕분에 출판 기회를 얻게 되었습니다 감사합니다~

온라인 강의는 인프런에서 들을 수 있습니다! (https://www.inflearn.com/course/팀개발-깃-깃허브?inst=78af1b7b)


Git을 왜 쓰는지 궁금하고, Commit, Push, Pull 등의 개념부터 짚고 넘어가고 싶은 분들은 이 슬라이드를 먼저 참고하시면 됩니다.

대상

본 자료는 간단한 git-flow로 Github에서 협업을 하는 과정을 설명한 글입니다.
초심자를 대상으로 하며, SourceTree를 사용합니다.

익힐 수 있는 개념

commit, push, branch, merge, rebase, pull request, release, fork


PART 1. 단일 저장소에서 협업하기

토끼와 거북이- image.003

개발자 토끼와 거북이가 달리기 대회 사이트 ‘달사’를 만들려고 합니다
토끼는 메인 페이지를, 거북이는 대회 신청 페이지를 만들기로 했습니다.

그런데 각자 코딩을 하면, 이를 어떻게 합쳐서 하나의 ‘달사’로 만들까요?
토끼와 거북이는 이에 대한 수단으로 git을 사용하기로 했습니다.

토끼와 거북이- image.004

토끼는 https://github.com/ 에 가입해서  ‘dalsa’라는 이름의 새로운 저장소를 만들었습니다.
Public으로 만들어 누구나 이 프로젝트에 참여할 수 있게 할 거예요.
* Organization 을 만들어 단체의 이름으로 저장소를 만들 수도 있습니다

토끼와 거북이- image.005

원격(Github 사이트)에 dalsa 저장소가 생겼습니다.
이젠 여기에 코딩을 하기 위해 로컬(내 컴퓨터)에 저장소를 다운받아야 합니다.

토끼와 거북이- image.006

토끼는 먼저 git을 설치하고, (https://git-scm.com/book/ko/v2/시작하기-Git-설치) SourceTree의 ‘+New Repository > Clone from URL’을 사용해서 저장소를 받아옵니다.
SourceTree, Github Desktop같은 GUI 프로그램은 시각적으로 상태를 확인할 수 있다는 장점이 있지만 CLI의 모든 기능을 지원하지 않습니다.
개인이 이해하기 쉬운 것 먼저 배우셔도 되지만, CLI로 하는 법은 처음이든 나중이든 필수로 익히셔야 합니다.
CLI로 git을 설치하고 사용하는 방법은 git 간편 안내서 를 참고해주세요.

토끼와 거북이- image.007

토끼는 제일 먼저 저장소에 대한 설명인 README.md 파일을 만들었어요.
이를 원격에 올릴거예요.

깃에 커밋을 하는 올릴 파일은 3가지 상태가 있습니다.
이를 ‘포장하는 과정’이라고 생각해 볼게요,

  1. 포장 전인 파일들: Unstaged Files
  2. 포장하기로 한 파일들: Staged Files
  3. 포장 완료 파일 묶음: Commit
토끼와 거북이- image.008

README파일을 체크해서 ‘이 파일을 포장할거다’라는 Staged단계로 올립니다.
지금은 한 파일밖에 없지만, 나중에 변경 내역이 여러 파일에 있으면 내가 원하는 것들만 선택해서 staged로 올릴 수 있겠죠?
이는 ‘README 파일 추가’란 이름을 붙여서(commit message) 선물로 포장할거예요(commit).

토끼와 거북이- image.009
토끼와 거북이- image.010

이렇게 코드를 의미있는 단위로 쪼개서 포장하는 것이 Commit 입니다.
각 커밋별로 변경된 이력을 편하게 볼 수 있고, 예전에 올렸던 커밋으로 코드를 돌려 시간여행을 할 수 있습니다.
오프라인 상태에서도 가능해서 비행기나 산 꼭대기에서도 커밋할 수 있죠(?)

토끼와 거북이- image.011
토끼와 거북이- image.012

이렇게 커밋만 하면 내 컴퓨터에만 저장되어 있고 Github사이트엔 아직 올라가지 않은 상태입니다.
이 커밋들을 진짜 올리기 위해 Push를 합니다.
Push를 누르면 git이 우리 컴퓨터 폴더에 숨겨져 있는 .git파일을 참조해 그 곳에 저장된 달사 저장소 url에 코드를 올려줍니다.

토끼와 거북이- image.013

Github 저장소에 가 보면 잘 올라와 있는 것을 확인할 수 있습니다.

토끼와 거북이- image.015

이렇게 바로 올린 코드는 Master 브랜치(기본적으로 생김)에 올라갔습니다.
브랜치는 단어 그대로 가지를 뻗어 나가는 것입니다.

토끼와 거북이는 Master 브랜치엔 완벽한 코드만(언제든지 배포할 수 있는) 두자는 약속을 했습니다.
그래서 ‘개발 중’인 코드를 올리기 위한 dev브랜치를 새로 만들었습니다.

토끼와 거북이- image.014

특정한 코드 상태에서 브랜치를 따면 새로운 브랜치에서 독립적으로 작업하고 나중에 합칠 수 있습니다.
위의 예시에서 브랜치 없이 둘이 한 종이에 작업했다면 서로 같은 곳을 수정했을 때 (잡은 손 고치기) 에러가 났겠죠.
브랜치로 작업하면 추후에 합칠 때 원하는 손 그림을 택하면 됩니다.

토끼와 거북이- image.016

둘은 짝 코딩으로 사이트 뼈대를 만들어 dev 브랜치에 커밋 후 푸시했습니다.
좌측 메뉴의 branch에서 dev, master를 더블 클릭해서 각 브랜치를 옮겨다닐(checkout) 수 있습니다.

토끼와 거북이- image.017

초기 세팅을 마친 거북이와 토끼는 서로 나뉘어서 코딩을 하기로 했습니다.

토끼는 메인 페이지를 만들기 위해 ‘feature/main’이란 이름으로, 거북이는 달리기 신청 폼을 만들기 위해 ‘feature/form’이란 이름으로 dev브랜치의 최신 커밋으로부터 새로운 브랜치를 만들었습니다.
브랜치 앞에 ‘feature/‘처럼 슬래시로 구분된 이름을 달아주면 이 구분별로 브랜치를 묶어볼 수 있는 장점이 있습니다.

토끼와 거북이- image.018

토끼와 거북이가 각자 브랜치에서 코딩을 합니다.
시간이 흘러 토끼가 main 페이지를 다 만들어 dev브랜치에 ‘feature/main’브랜치를 합치려 합니다.
하지만 예고 없이 바로 합치기보다는 거북이에게 리뷰를 먼저 받고 합치고 싶습니다.

그러기 위해 하는 것이 Pull Request입니다.

토끼와 거북이- image.019

Github저장소에 있는 ‘Pull Request’버튼을 눌러
‘feature/main’에서 ‘dev’브랜치로 Pull Request(땡김 요청)를 보냅니다.

토끼와 거북이- image.020

그럼 저장소의 ‘Pull requests’섹션에서 토끼가 보낸 풀리퀘를 확인할 수 있습니다.
Files changed를 보니 잘 만들었네요 (맘에 안 들면 거부할 수 있습니다).
하단의 ‘Merge pull request’를 눌러 토끼의 커밋들을 dev브랜치에 합칩니다.

토끼와 거북이- image.021

그 와중에 거북이도 폼 제작을 마쳤습니다.
dev 브랜치(c)에 Pull Request를 보내려 보니 토끼의 새로운 코드가 추가되어 거북이가 처음에 땄던 dev 커밋(a)과 상태가 달라졌군요.
a와 b는 바로 합칠 수 있는데 b와 c를 섣불리 Merge 했다가는 서로의 코드가 충돌날 수 있겠는데요?
만약 거북이와 토끼가 같은 코드를 다르게 고쳤다면 에러가 나겠죠.

토끼와 거북이- image.022

사려깊은 거북이는 ‘선-머지 후-풀리퀘’를 보내기로 합니다.
dev의 최신 커밋(c)에서 마우스 오른쪽 버튼을 눌러 Merge를 합니다.
그랬더니 Merge Conflicts가 나네요.

토끼와 거북이- image.023

토끼와 거북이 둘 다 타이틀을 고쳤네요.
코드를 보니 거북이의 코드가 맞는 버전입니다. 회의에서 다정 버전으로 하자고 결론이 났거든요.
수동으로 토끼의 코드를 지우고 거북이의 코드를 남겨 commit+push합니다.

토끼와 거북이- image.024
토끼와 거북이- image.025

거북이도 dev로 Pull request를 보냅니다.
토끼가 확인하고 merge하니 오류 없이 잘 됩니다.
거북이의 ‘feature/form’에는 dev브랜치의 코드도 잘 섞여있는 버전이 들어가 있었기 때문이죠.

이제 dev에 토끼의 ‘메인 페이지’와 거북이의 ‘신청 폼’이 모두 반영된 깔끔한
코드가 올라왔습니다.
이 정도면 베타 버전으로 출시해도 되겠어요!

토끼와 거북이- image.026

배포를 위해 dev에서 master 브랜치로 pull request를 보내고 머지를 합니다.
출시 가능한 버전이니까 master에 두면 되겠지요?

그럼 한번 출시를 해볼까요?

저장소에서 ‘releases’를 누르고, 이번 업데이트의 버전과 세부 내용을 적어준 뒤 Publish Release 버튼을 누릅니다. (일반적인 버전 관리 규칙)

토끼와 거북이- image.027

첫 번째 릴리즈가 완성되었습니다!

우리 서비스가 업데이트 되는 기록을 남길 수 있고,  그 당시의 소스코드를 다운받을 수도 있습니다. 만약 이번 업데이트에 치명적인 버그가 있다면 지난 버전으로 빠르게 롤백할 수도 있습니다.

토끼와 거북이- image.028

React처럼 잘 관리되는 오픈소스의 저장소 release 노트를 보면
그 소스가 어떻게 관리되고 있는지 깔끔하게 확인할 수 있겠죠 🙂

토끼와 거북이- image.029

이렇게 커밋을 하고 git에 올렸을 때의 또 하나의 장점은 언제든지 어떤 상태로든 시간여행을 할 수 있다는 것입니다.

‘feature/main’브랜치에서 메인 페이지를 만들다가 ‘feature/comment’브랜치로 넘어가서 댓글 기능을 개발할 수도 있고, 거북이가 개발중인 ‘feature/request’로 넘어가서 거북이의 코드를 돌려볼 수도 있고, 내가 코딩을 이상하게 했을 때 내 브랜치의 기존 버전으로 reset할 수도 있습니다.


PART 2. Fork해와서 협업하기

토끼와 거북이- image.030

토끼와 거북이가 만든 ‘달사’가 흥했습니다. 너굴맨이 사이트를 써 보니 ‘댓글’기능이 있으면 좋을 것 같다는 생각이 들었습니다. 달사는 오픈소스니까 너굴맨이 기능을 추가해서 기여(contribution) 할 수 있죠.

달사 github repository페이지에서 Fork버튼을 누릅니다. 그러면 너굴맨의 계정으로 리포지토리가 복사됩니다.

토끼와 거북이- image.031

토끼와 거북이가 했던 방법처럼 원격 repo를 로컬에 받아오고, 댓글 기능을 커밋합니다.
Master 말고 Dev의 최신 커밋에서부터 작업해야 나중에 Pull Request를 Dev로 보낼 수 있겠죠? 토끼와 거북이의 Master에는 배포 가능한 코드만 들어가야 한다는 규칙이 있으니까요.

토끼와 거북이- image.032

믿음직스러운 너굴맨은 Pull request를 보내기 전에 토끼와 거북이의 원본 저장소에 변경 사항이 없나 확인합니다. 여기는 너굴맨이 fork뜬 저장소이기에 원본 저장소의 최신 커밋들을 볼 수 없습니다.

너굴맨은 Remotes > New Remote로 원본 저장소의 url을 ‘upstream’이라는 이름으로 추가해줍니다.

토끼와 거북이- image.033

그 와중에 토끼와 거북이가 열일해서 너굴맨이 딴 c커밋에서부터 검색 기능(a커밋)을 dev브랜치에 새로 추가했네요. 그냥 Pull request를 보내면 충돌이 일어날 수도 있겠습니다.
여기서 선머지 후풀리퀘스트를 할 수도 있겠지만, 깔끔한 코드 히스토리를 남기고 싶은 너굴맨은 ‘Rebase‘를 하기로 합니다.

토끼와 거북이- image.034

Rebase는 단어 그대로, 다시 베이스를 정하는 것입니다. 너굴맨의 코드는 C커밋에서 따서 현재 a커밋과 머지했을 때 충돌이 일어날 수 있습니다. 하지만 a커밋에서 브랜치를 땄다면 충돌 없이 한 번에 머지를 할 수 있겠죠? 여기서 a커밋에서 브랜치를 딴 것처럼 히스토리를 조작하는 것이 Rebase입니다.

토끼와 거북이- image.035

새로 베이스로 삼고 싶은 a커밋에서 ‘Rebase’를 눌러줍니다.
(충돌이 난다면 고쳐줍니다. Merge할 때 충돌 해결하는것과 동일하게 해 주시면 됩니다. 충돌 해결을 하면 다시 commit을 눌러주세요.)

그러면 내 컴퓨터에는 b커밋이 c에서 딴 게 아닌 a에서 땄던 것처럼 히스토리가 조작됩니다. 근데 이를 원격 저장소에도 push하려면, 그냥 push로는 에러가 납니다. 히스토리를 망가뜨리는 위험한 push니까요. 그래서 콘솔 창에서 ‘git push -f origin’이라는 명령어로 force push를 해 줍니다(소스트리에는 force push 기능이 없습니다).

이는 다른 사람이 이 브랜치를 수정하고 있을 가능성이 제로일 때만 해야합니다.

토끼와 거북이- image.036

fetch를 한 번 눌러 원격과 내 소스트리를 동기화 해줍니다.
베이스가 옮겨졌네요! 기존에 거북이가 머지를 했을 때는 ‘Merge pull request 어쩌고’ 이런 머지 커밋이 안 예쁘게 남았는데, 이제는 바로 깨끗하게 머지를 할 수 있는 상태가 되었습니다.

토끼와 거북이- image.037

포크된 내 리포지토리에서 pull request버튼을 누릅니다.
base fork를 토끼와 거북이의 dev브랜치, head fork를 너굴맨의 master브랜치로 해 줍니다.

토끼와 거북이- image.038

토끼가 확인했네요! 맘에 들었나 봅니다. 너굴맨의 코드를 머지했습니다.

토끼와 거북이- image.039

이제 너굴맨은 달사의 contributer로 등록되고, 너굴맨의 개인 페이지에도 달사 저장소가 뜨게 됩니다. 너굴맨 달사 커미터 축하!

토끼와 거북이- image.040

이렇게 토끼와 거북이가 단일 리포지토리에서 협업하는 것, 너굴맨이 오픈소스에 기여하는 것을 ‘달사’ 서비스 만들기를 예를 들어서 설명하였습니다.

개선점이나 피드백 해주시면 감사하겠습니다 🙂
모쪼록 처음 Github으로 협업을 하시는 분들께 도움이 되었으면 합니다.

토끼&거북이의 저장소: https://github.com/milooy/dalsa
너굴맨의 저장소: https://github.com/CODEINAE/dalsa

Published by

Yurim Jin

아름다운 웹과 디자인, 장고와 리액트, 그리고 음악과 맥주를 사랑하는 망고장스터

35 thoughts on “초심자를 위한 Github 협업 튜토리얼 (with 토끼와 거북이)”

  1. 개념을 쉽게 잘 정리해놓으신 것 같습니다. 습관적으로 사용하면서 개념을 모르고 사용한게 부끄러울 따름입니다. 좋은 정보 감사합니다.

  2. 늘 부분적인 테크닉 강좌만 봐왔었는데 이렇게 한눈에 보기 쉽게 알려주셔서 감사합니다!ㅜ.ㅜ

  3. 소스트리에도 force push가 추가 되었습니다. 1.7버전 이상부터 Preferences -> General -> Allow force push 체크박스를 선택해준다면 푸쉬창에 force push 체크박스가 생깁니다.

  4. 중요한 부분을 이해하기 쉽게 풀어써주셨네요. 좋은정보 감사합니다 수고하셨어요 🙂

  5. 그림이 귀여워서 재밌게 잘 읽었습니다. github를 이용한 협업을 이해하는데 아주 도움이 됐습니다. 감사합니다.

  6. 그러면 내 컴퓨터에는 b커밋이 a에서 딴 게 아닌 c에서 땄던 것처럼 히스토리가 조작됩니다. 근데 이를 원격 저장소에도 push하려면, 그냥 push로는 에러가 납니다. 히스토리를 망가뜨리는 위험한 push니까요. …. -> 이부분 a, c가 맞는 내용인가요? 헷갈리네요ㅠㅠ

    1. b커밋이 c에서 딴 게 아닌 a에서 땄던 것처럼이네요. 감사합니다. 수정했습니다.
      (다음 revision은 밑에서부터(시간 순서대로) a, b, c로 그림을 바꿔야 겠네요 ㅎㅎ 지금은 a가 먼저 일어난 커밋같은 느낌이…)

  7. 좋은 정보 감사합니다.
    혹시 해가 되지 않는다면 블로그에
    공유하고 싶은데,
    문제 시 연락 부탁드립니다..

  8. 여전히 깃허브는 뭔가 개념정리가 잘안되었는데 두번째 보내요. 이제 좀 이해가 되는 것 같습니다.

  9. 팀프로젝트하면서 필요한 지식이었는데 감사합니다. 초보자도 잘 이해할 수 있었습니다!

  10. 안녕하세요! 항상 그리고 이번 포스팅 역시 너무 잘 봤습니다! 처음으로 댓글 남기네요. 그림도 너무 귀엽고 적절한 예시라서 처음 접하는 분들이 이해하기 쉬울 것 같아요! 제가 동아리 내에서 간단하게 git에 관한 세미나를 하려고 하는데 혹시 발표자료에 그림을 좀 써도 될까요?? 물론 출처 남기겠습니다! 🙂

  11. 이래저래 헷갈렸던 개념들 너무 깔끔하게 설명해주셨네요, 도움 정말 많이 받았습니다 감사합니다 🙂

  12. 여기저기 흩어졌던 개념들이 한번에 정리된 느낌이에요. 정말 많은 도움이 됐습니다. 감사합니다!

  13. 깃허브 개념을 제대로 이해하지 못하고 사용했었는데 너무 좋은자료 만들어주셔서 감사합니다~!!!!!

  14. git의 개념이 알쏭달쏭해서 제대로 쓸 엄두조차 못 내고 있었는데 이젠 더 이상 안 헷갈릴 자신 있어요! 감사합니다 🙂

  15. 본문에 아래처럼 적으셨는데…..
    “Master 말고 Dev의 최신 커밋에서부터 작업해야 나중에 Pull Request를 Dev로 보낼 수 있겠죠? 토끼와 거북이의 Master에는 배포 가능한 코드만 들어가야 한다는 규칙이 있으니까요.”

    fork된 곳의 작업은 dev가 아닌 master에서 하고 upstream의 dev에 PR하신거죠?

    1. 네 맞습니다~ 블로그 글에서는 fork된곳은 master브랜치에서 개발했어요.
      실제로 개발 하실 때는 어느 브랜치에서 해도 무방합니다 ㅎㅎ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s