Github 공동작업을 위한 안전한 fork 사용법(1)

Updated:

(본 글은 Fork 사용 방법에 대한 글이지만, 현재 사이트의 공동 집필 환경을 위한 Fork 사용법에 포커스하여 작성하되었습니다. 여기에 사용된 예시들은 일반적인 상황과 맞지 않을 수 있음을 양해 구합니다.)

코로나19 사태의 위기가 우리 공동 집필진 분들에게는 오히려 그동안 갈고 닦은 내공을 대방출할 기회를 제공해 준 것 같습니다. 이에 불철주야 인고의 블로그 작성에 전념하시는 집필진 분들이 조금은 더 수월하게 작업할 수 있도록, 저 또한 일천한 경험을 바탕삼아 본 글을 기획하게 되었습니다. 짧은 3주동안 git과 GitHub와 사투를 벌이며? 얻게 된 얕은 지식이지만 도움이 되길 바랍니다.

Intro …

GitHub에서 공동작업을 할 경우, conflict 방지를 위해 대부분 각자의 브랜치(branch)를 이용하여 작업을 하게 된다. 브랜치를 사용하면, 로컬 작업 후 master 브랜치로 바로 push하지 않고 각자 만든 원격 브랜치로 push한 후에, pull request를 하여 merge 작업을 할 수 있어서 보다 안전하게 GitHub 공동 작업을 할 수 있다.
(여기서 안전하다는 말은 강제 push로 남의 소스를 밀어버리는 극악무도한 경우를 피하게 된다는 의미 )

Pull vs Pull Request

pull request는 Pull과 반대의 의미를 갖고 있는데, pull은 원격 리파지토리의 변경사항을 로컬로 당겨오는 반면, pull request는 원격 리파지토리가 내 브랜치의 변경사항을 당겨가도록 요청을 하는 것이다. 궁극적으로 내 브랜치에서 발생한 변경사항을 remote 리파지토리가 알아차리고 반영하게 한다는 점에서 push와 비슷하지만 주요한 차이가 있다.
pushPull request

- 로컬 to 원격으로만 push가 가능

- 원격 브랜치 사이에서만 pull request가 가능

- push와 동시에 내부적으로 merge가 발생

- 유보된 merge라고 하며 pull request만으로는 merge되지 않음 (pull request를 승인하는 과정 중에 merge가 발생)

pull request가 생성되면, 요청받은 리파지토리에서 pull request를 승인해야 실제 merge가 되면서 마무리된다. Pull request를 하게 되면 두 단계에 걸쳐 소스 반영이 되므로 약간 번거로운 측면이 있지만, 우아하고 안정적으로 소스를 merge할 수 있다.

[Pull 관련 글]
[pull request 관련 글]


그런데, GitHub에 단순히 소스를 올리는 작업이 아니라, 블로그로 포스팅을 해야 한다면 어떻게 될까?

각자의 로컬에서 작업한 소스파일(주로 MD 또는 image파일들)을 GitHub 원격 리파지토리의 작업 브랜치에 올리고, master 브랜치쪽으로 pull request를 생성한 후에 다시 master 브랜치에서 해당 pull request를 승인하면서 최종적으로 소스 merge가 수행되고 나서야, 실제 브라우저에서 작동되어 나온 블로그 결과물을 확인할 수 있을 것이다.

merge by push merge by pull request

만약 merge 작업까지 모두 마치고 나서 결과물을 확인했는데 오타나 깨진 이미지를 발견했다면, 이미 대중에게 공개된 상황에서 급히 소스에서 수정하여 다시 merge까지 하느라, 위와 같은 push > pull request > merge pull request 과정을 수십번 삽질하게 되는 상황이 올 수도 있다. ( 아래는 반복된 삽질의 흔적 😅)

또한 잘못된 글귀를 고치느라 시간이 소요되는 동안, 많은 방문객이 이미 왔다 갔다면 수십번의 삽질의 노력에도 불구하고, 오타와 깨진 이미지가 이미 널리 공개되어버리는 난감한 상황이 될 수도 있다.
자, 이런 경우를 어떻게 해결해야 할까?
여러분은 이미 브랜치를 사용하여 pull, push, pull request 기능을 마스터하였다. 그렇다면 이제부터 fork를 이용하여 “따로 또같이”의 공동작업을 해보면 어떨까?

일단 Fork를 해보자.

fork라고? UNIX에서 사용하던 그 fork와 같은 명령어다. UNIX에서 fork를 배울 때 이론만으로는 이해가 안되고, 직접 실습을 통해서 이해가 되었던 적이 있다. GitHub의 fork도 비슷하다. 직접 해봐야 안다.

대상 리파지토리 우측에 보면 fork라는 조그만 네모박스가 있다.

오른쪽에 숫자가 있는데, 이것은 이미 fork를 해간 숫자이다. 눌러서 누가누가 fork했는지 살짝 들여다본 후, 과감하게 Fork를 누르면…. 바로 Fork가 진행된다. (놀라지 마시라)

순식간에 뚝닥 자신의 리파지토리로 복제가 된다. 원래의 리파지토리 안에 있던 모든 소스와 로그가 고스란히 내 리파지토리로 생겨난 셈이다.

차이점은 위 그림과 같이 상단에 GitHub 계정명이 다르게 나타난다는 점이다. (원래는 GitHub계정명/engineering-skcc.github.io로 생기는데, 위에서와 같이 자신이 선호하는 이름으로 변경이 가능하다. 이 부분은 2편에서 설명)

또 하나의 차이점은 상단 메뉴에 Settings가 나타난다. Original 리파지토리와 달리 fork 리파지토리는 내 소유가 되므로 Settings를 통해 원하는대로 변경관리가 가능하다.

이제 이 fork 리파지토리를 통해 내맘대로 블로그 페이지에 대한 테스팅도 가능하게 되었다.

Fork 리파지토리를 사용하면 뭐가 좋을까?

fork의 긴 여정을 떠나기 전에 우선 뭐가 좋은지부터 알아두는 게 좋을 거 같다.

1) 하나의 브랜치로 편하게 작업 가능

일단, original 리파지토리와는 별도로 fork 리파지토리에서 작업을 하게 되므로, 잘못 혼돈하여 original의 master를 건드릴 염려가 없다.

공동 작업할 경우, 자신의 브랜치로 체크아웃하지 않고 master에서 작업하다가 종종 소스가 꼬여 버리는 경우가 있는데, fork해온 리파지토리는 온전히 자신만의 것이므로 굳이 another 브랜치를 만들 필요없이 default인 master 브랜치에서 작업해도 된다.

2) Private 리파지토리를 유지하면서 publish도 가능

이게 무슨 말이냐…. GitHub에서는 리파지토리를 만들 때마다 private인지 public인지를 결정해야 한다.

유료라고 한다면 걱정할 필요가 없는데, 무료 계정을 사용할 경우 private 리파지토리에서는 아쉽게도 웹사이트처럼 publishing이 불가능하다.

웹브라우저에서 블로그를 확인하려면 Publising이 필수이므로 어쩔 수 없이 public 옵션을 선택해야 하는데, public이라 함은 리파지토리 소스가 외부에 공개될 뿐 아니라 아무나 다 내 리파지토리에 커밋을 할 수 있게 된다. 헐…

따라서, 아무나 내 리파지토리를 못 쓰게 하려면 private으로 잠가야 한다.
그런데, fork를 하게 되면 original 리파지토리의 속성이 유지된다.

우리의 original 리파지토리가 private이었기 때문에, private하게 유지가 되면서 publishing도 가능한 것이다.

Settings > Options 메뉴에서 하단으로 죽 이동하면 다음과 같은 메시지를 확인할 수 있다.

만약, fork를 하지 않고 그냥 리파지토리 복제를 한다면 어떻게 될까?

이 경우에는 Original 리파지토리의 속성을 따르는게 아니라, 위에서 언급했듯이 그냥 본인 계정의 유료 여부에 따라 사용범위가 제한된다.

3) Original 사이트가 아닌 곳에서 나만의 작업 페이지 확인

Fork를 권장하는 궁극적 목적이 바로 이 때문이다.

Original 리파지토리에서는 master로 merge 작업까지 마쳐야 확인할 수 있었던 블로그 페이지들을 이제 나만의 fork 리파지토리에만 변경된 사항을 push하고, 바로 확인이 가능하다. 짠~~

Original 사이트인듯, Original이 아닌 Original 같은 사이트~~

저 위의 URL을 보면, Original 사이트와 주소가 다르다. 짝퉁 사이트인 셈이다. 😃 Fork를 사용하니 하고 있는 작업들이 좀 편해질 것 같은 생각이 드는가? 이제, 본격적으로 작업에 들어가보자. 위와 같은 결과물을 얻기 위해서는 해야 할 일들이 좀 있다.

Fork 리파지토리 설정하기

Fork 리파지토리를 가지고, 나만의 작업할 수 있는 환경을 만들어보도록 하자.

리파지토리 이름 변경

Settings > Options 메뉴로 들어가면 가장 먼지 리파지토리 이름이 나온다. 기존 명칭과 다르게 나만의 이름을 지어보자. Rename 버튼을 눌러야 실제로 반영이 된다.

위와 같이 하여 fork해온 리파지토리의 이름을 바꿀 수 있다.

Publishing을 위한 설정

리파지토리 이름을 변경한 후에 화면 아래로 스크롤을 해서 내려가면 다음과 같이 GitHub Pages 세팅 화면이 나타난다. Source 부분의 None을 눌러서 포스팅할 재료를 선택하도록 하자.

master 브랜치를 선택하면 다음과 같이 화면이 바뀔 것이다. 퍼블리싱될 주소 위치도 바뀌어 나타나는 것을 확인할 수 있다.

자 이제 여기까지 했으면, 90%의 준비가 끝났다.

Full Path 문제

Publishing URL을 눌러 짝퉁 사이트가 생겼는지 확인해보자. 아마도 뭔가 되는 것 같기는 한데… 뭔가가 좀 이상한 것 같기도 하고… 이상한 점을 발견했다면 당신은 좀 대단한 사람? 😙

짝퉁사이트에 포스팅된 글의 링크나 이미지들의 경로를 확인해보자. 아마도 “https://engineering-skcc.github.io/~”로 시작하는 주소를 달고 있을 것이다. 이는 포스팅 소스 안에 링크나 이미지 주소를 작성하면서 전체 경로, 즉 “https://”로 시작하는 full path를 지정했기 때문일 것이다.

Original 리파지토리의 원본 이미지를 링크하고 있어도 지금 상태에서는 문제가 없겠지만, 앞으로 fork 리파지토리에서 새로운 글과 이미지를 올리게 된다면 해당 이미지는 경로가 맞지 않아 확인을 할 수 없게 된다. 따라서, 새로 생긴 사이트에 맞게 Path가 적용되게 하기 위해서 포스팅용 MD 파일에서 “https://engineering-skcc.github.io/~”의 꽉 찬 절대경로 대신 “/”를 사용하도록 해보자.

먼저 우리의 편집기인 Visual Studio에서 Image Prefix를 바꾸어주고, 내부 리소스를 참조한 링크도 모두 찾아서 바꾸어주도록 하자.

약간 귀찮을 수 있지만, 요새는 에디터가 워낙 좋아서 순삭이다. 무엇보다, 우리가 포스팅한 “https://engineering-skcc.github.io/~”의 경로는 언제든 다른 곳으로 바뀔 수 있다. 따라서 저렇게 full path를 사용하는 것은 바람직하지 않다. 망설이지 말고 본인의 소스에서 저런 링크를 찾아 모두 바꾸도록 하자.

단, 바꿀 땐 바꾸더라도, 본인이 작성한 MD 파일만 바꾸고, 남의 글은 건드리지 않도록 한다. 나중에 merge시 남의 소스와 충돌이 나지 않으려면… Fork 리파지토리에서 Path를 모두 바꾸는 작업을 한 뒤, commit / push하고 제대로 반영되었는지 다시한번 확인해 보자. 짜자…. 잔…. 어라?

Root Path 문제

아마도 아까보다 더 이상해진 상황을 접하게 될 것이다. 그나마 Original 사이트에서 끌고 오던 이미지조차 보이지 않게 되었다. 이번엔 무엇이 문제일까?

애석하게도 GitHub에서 포스팅되는 모든 서비스 루트 디렉토리는 “https:// … github.io/”이다. 어떤 리파지토리를 만들더라도 포스팅하는 모든 GitHub페이지의 홈 디렉토리는 본인의 GitHub 계정 주소가 된다. 그런데, 내부의 다른 페이지나 이미지 링크시에는 본인의 리파지토리 이름을 붙여서 “https:// … github.io/repository name/” 또는 “/repository name/”와 같이 Prefix를 붙여야 한다.

하지만, 우리가 원본 리파지토리에서 이러한 repository name을 생략할 수 있었던 것은 GitHub가 계정명과 동일한 리파지토리를 사용할 경우 repository name이 들어간 경로는 생략할 수 있도록 해주기 때문이다. (음…. 이해시키기가 대략 난감 😥)

다시 말하면, Original 리파지토리에서는 홈페이지 주소가 “https://engineering-skcc.github.io/engineering-skcc/”가 되어야 하지만 계정명과 동일한 리파지토리에 대해서는 GitHub가 융통성 있게 “https://engineering-skcc.github.io/”을 홈페이지로 인식하게 해준다. 따라서 내부 리소스 참조시 리파지토리 이름을 경로에서 생략하여 “/”만 사용해도 알아서 리소스를 찾아 인식한다.

하지만, 짝퉁 사이트의 경우에는 홈페이지가 “https://본인의 GitHub계정명.github.io/fork repository name/”과 같이 되며, 내부 리소스 참조시 “/fork repository name/”을 사용해야 한다.

따라서, 이를 해결하는 방법은 “https://본인의 GitHub계정명.github.io/fork repository name/”으로 된 홈페이지 주소를 “https:// ~.com/” 과 같이 바꾸어 주고, 이 주소를 홈페이지 루트로 인식하게 만들면 된다.

Custom Domain 설정하기

GitHub에서는 default로 설정되는 퍼블리싱 URL을 다음의 설정 기능을 이용하여 바꿀 수 있다.

blog.my-domain.com 또는 my-domain.com과 같은 식으로 나만의 도메인 이름을 지어보자. 그리고, Save 버튼을 누르면 다음과 같이 fork 리파지토리의 루트 아래에 CNAME file이 생성된다.

그리고 이와 같이 생긴 CNAME 파일이 Original 리파지토리에 병합되지 않도록 하기 위해 .gitignore 파일을 열어 그 안에 CNAME 파일명을 반드시 추가하자. 이미 추가되어 있다면 PASS~~

[ CNAME 파일 주의사항 !! ]

  • CNAME 파일을 .gitignore에 추가하더라도 .gitignore의 역할은 해당 파일 변경시 커밋에서만 제외시켜줄 뿐, pull 또는 pull request에는 관여하지 않는다.
  • 따라서, 본인의 fork 원격지에서 변경한 내용은 pull request에 의해 그대로 원본 master에도 반영이 되고, 다른 사람이 원본 master로부터 자신의 fork 로컬 저장소로 pull을 하면 그 로컬에서도 CNAME이 바뀌게 된다.
  • 그런데, CNAME 파일은 fork 사이트의 도메인 주소를 redirect해주는 역할이기 때문에 사실 로컬에 있을 필요도 없고 로컬에서는 굳이 수정할 필요도 없다.
  • 결론 :
    • 누군가 fork 사이트를 만들고 CNAME을 바꾸게 되면 원본 master의 CNAME도 바뀐다.
    • 이를 각자 로컬에 받아내리면 다른 사람의 도메인 주소가 반영된 CNAME 파일로 변경되는데, 그렇다 하더라도 무시하자.
    • .gitignore가 제대로 동작하면 본인의 fork 원격 저장소는 그대로 유지될 것이다.


이제 브라우저에서 새로 생긴 주소로 접속해보자.

애석하게도 연결이 거부될 것이다. 마지막으로 한가지가 더 남아 있다. 마지막 스텝이다.

hosts 파일에 domain 주소 추가하기

우리가 새로 만든 도메인 주소는 공식적인 DNS에 등록되어 있지 않기 때문에 서비스되지 않는다. DNS에 등록하지 않고도 나오게 하려면 hosts 파일에 ip와 해당 주소를 등록하면 된다. 다음과 같이 hosts 파일에 등록하자.

	185.199.111.153		my-domain.com
	185.199.110.153		my-domain.com
	185.199.109.153		my-domain.com
	185.199.108.153		my-domain.com

185.199.xxx.153는 GitHub 사이트의 IP주소이다.

이제 내가 설정한 domain 주소로 접속을 해보자. 모든 것이 제대로 동작되는 것을 확인할 수 있을 것이다.

짝퉁 사이트가 무난히 동작되는 것을 확인했으니, 이제 (3)편에서는 Fork 리파지토리에서 변경한 소스를 Original로 다시 어떻게 반영해야 하는지에 대해서 알아보도록 하자.

Fork 리파지토리에서 원본과 동기화하려면 ?

Fork 리파지토리를 Original에 반영하려면 ? 또는 Original에서 최근 변경된 사항을 다시 Fork 리파지토리로 갖고 오려면 ? Fork 리파지토리가 나만의 작업환경이라 말하였지만, 공동작업을 위해 결국 어느 순간에는 Original 리파지토리와 merge를 해야 할 것이다. Fork 리파지토리를 잘 다루기 위한 방법들을 알아보자.

1. 먼저 로컬로 Clone or Download하기

Fork 리파지토리도 GitHub라는 원격 저장소에 있기 때문에, 빠른 작업을 하기 위해서는 기존에 하던 것처럼 본인의 로컬로 다운로드받아야 한다.

원래 사용하던 로컬 저장소와는 다른 곳에서 다운로드되도록 하자.

  $ cd ~/Documents 
  $ git clone [ Fork 리파지토리 URL ]

Fork 리파지토리에서는 master 브랜치를 그대로 사용해도 된다. 나만의 작업용 브랜치를 만들어도 된지만, GitHub Page 페이지에서는 master 브랜치의 소스만을 사용하기도 하고, 자신의 master브랜치와도 병합을 해주어야 하므로 약간의 귀찮음이 발생한다. 그냥 master를 사용하되 Original의 master와 헷갈리지 않도록 하자.

2. origin에 push하기

Fork 리파지토리의 로컬 작업 후, 의도했던대로 짝퉁 사이트에서 확인하기 위해 Fork 원본 리파지토리에 반영하고 싶은 경우에는 어떻게 해야 할까 ? 먼저 지금 작업환경이 환경이 Fork 리파지토리인지부터 확인을 해보자.

  $ git status 
    On branch master
    Your branch is up to date with 'origin/master'.
    ...    

그리고 기존과 다를 게 없이 똑같이 스테이징에 올리고 커밋 후에 푸시하는 명령어를 입력하면 된다.

  $ git add .
    ...
  $ git commit -m "this changes are in forked repository .... "
    ...
  $ git push origin master
    ...

위에서 origin은 로컬 입장에서 바라본 원본 저장소를 가리키며, 또한 원격 Fork 리파지토리를 의미한다. (origin … 이런 건 git을 대충이라도 공부하면 다 알게 된다. 긴 설명은 생략…)

push를 통해 원격 반영이 끝나면, 처음에 “Fork를 사용하면 뭐가 좋은지”에서 설명했던 대로, 짝퉁 사이트에서 포스팅 페이지를 눈으로 확인할 수 있다.

3. Pull request 이용하기

짝퉁 사이트에서 확인해본 뒤 작업 결과물이 만족스럽다면, 여기서 끝나는 게 아니라 진짜 Original 리파지토리에 반영을 해야겠죠? Original 리파지토리로 보내기 위해 무엇을 해야 할까? 맞다. 우리가 이미 알고 있는 Pull request를 사용하여 요청하는 것이다.

앞서 언급한대로, Pull request는 원격 to 원격으로 하게 된다. 다음과 같이 GitHub의 Pull request 버튼을 이용하도록 하자.

그러면, 다음과 같은 화면이 나타난다. 왼편 base repository에 나타난 리파지토리와 브랜치 명이 바로 Original에 해당하는 것이다. 리파지토리와 브랜치명이 맞는지 다시한번 확인하고, 과감하게 Create pull request를 다시 클릭해본다. 순조롭게 진행이 될 것이다.


Pull request 생성 후에는 original master 브랜치에서 mergy pull requset를 눌러줘야 실제 완료가 된다는 점을 잊지 말자.


이제 fork 리파지토리를 만들어 내 작업을 반영할 수 있게 되었지만, 거꾸로 Orginal로부터 변경사항을 받아와야 할 필요도 있다.

해당 내용에 대해서는 다음 편을 참고하시라.