Skip to content
This page has been auto-translated and may contain errors.View in English

원격 저장소와 GitHub

docs.scrimba.com

지금까지 이 핸드북에서 다룬 모든 저장소는 한 곳에만 있었습니다: 바로 당신의 컴퓨터입니다. 이것은 노트북이 고장 났을 때 백업이 필요하거나, 다른 컴퓨터에서 프로젝트를 계속하거나, 다른 사람이 코드를 건드려야 할 때까지는 잘 작동합니다. 필요한 것은 관련된 모든 컴퓨터가 접근할 수 있는 곳에 저장소의 복사본을 두는 것입니다. 이 복사본을 원격 저장소(remote)라고 하며, GitHub는 대부분의 개발자가 이를 두는 곳입니다.

원격 저장소란 무엇인가 (그리고 GitHub는 어디에 들어맞는가)

**원격 저장소**는 당신의 컴퓨터가 아닌 다른 곳, 대부분 GitHub에 호스팅된 저장소의 복사본입니다. 저장소를 복제할 때, Git은 이미 하나를 설정해 주며, 기본값으로 origin이라는 이름을 붙입니다. git remote -v 명령을 실행하면 (이 -v 플래그는 URL뿐만 아니라 이름도 보여줍니다) 이를 볼 수 있습니다:

bash
$ git remote -v
origin  https://github.com/mara-chen/weather-app.git (fetch)
origin  https://github.com/mara-chen/weather-app.git (push)

Git이 알고 있는 모든 원격 저장소는 두 번씩 나열됩니다. 하나는 가져오기용이고, 하나는 밀어넣기용입니다. 이론상 두 주소가 다를 수도 있기 때문입니다. 실제로는 거의 항상 같습니다. origin은 복제할 때 Git이 자동으로 할당하는 별칭입니다. 이름을 바꾸거나 다른 곳을 가리키는 두 번째 원격 저장소를 추가할 수 있지만, 대부분의 프로젝트의 주 원격 저장소는 origin이라고 부릅니다.

이것은 초보자를 혼동시키는 구분을 다시 강조할 좋은 시점입니다: Git과 GitHub는 같은 것이 아닙니다. Git은 당신의 컴퓨터에서 실행되는 버전 관리 도구로, 아무것도 연결되어 있지 않더라도 커밋을 기록합니다. GitHub는 저장소의 복사본을 호스팅하고 밀어넣기와 가져오기를 할 수 있는 원격 저장소를 제공하는 웹사이트입니다. git remote, git push, git pull은 이 둘을 연결하는 명령어입니다. 이 명령어들은 당신의 노트북에서 실행되는 Git이 GitHub 서버에 있는 저장소와 통신하는 방식입니다.

원격 저장소는 저장소의 설정에 저장된 URL에 매핑된 이름일 뿐입니다. 그 옆에 Git은 **원격 추적 브랜치**를 관리합니다: 당신의 컴퓨터가 마지막으로 확인했을 때 그 원격의 브랜치가 어디에 있었는지를 기록하는 로컬 북마크입니다. origin/main이 바로 그것입니다. 이것은 GitHub에 있는 실제 main 브랜치가 아닙니다. 마지막 fetch나 pull 시점에 GitHub의 main이 어디에 있었는지에 대한 당신의 저장소의 기억입니다. 현재 Git이 가지고 있는 원격 추적 브랜치를 확인하려면 git branch -r 명령을 사용합니다:

bash
$ git branch -r
origin/main

원격 저장소가 하는 모든 것은 이 설정 항목과 이러한 추적 북마크를 통해 실행됩니다. 백그라운드 연결도 없고 변경 사항을 감시하는 것도 없습니다. Git은 fetchpull로 지시할 때만 원격에 대한 이미지를 업데이트합니다. 이것이 바로 이 장의 나머지 부분에서 다루는 내용입니다.

Juno원격 저장소란 무엇인가 원격 저장소는 다른 곳(보통 GitHub)에 호스팅된 저장소의 복사본이며, Git은 기본값으로 이를 origin이라고 부릅니다. 언제든지 git remote -v를 실행하면 저장소가 알고 있는 모든 원격 저장소를 볼 수 있습니다. Git과 GitHub는 같은 것이 아닙니다: Git은 당신의 컴퓨터에 있는 도구이고, GitHub는 당신의 원격 저장소가 있는 곳입니다. 이 구분을 일찍 명확히 하면 나중에 많은 혼동을 피할 수 있습니다.
Juno원격 저장소란 무엇인가origin은 단지 Git이 복제할 때 설정하는 원격 저장소의 기본 이름일 뿐이므로, 프로젝트가 필요하면 이름을 바꾸거나 더 많은 원격 저장소를 추가할 수 있습니다. git remote -v는 모든 원격 저장소의 fetch와 push URL을 보여줍니다. Git과 GitHub의 구분을 계속 염두에 두세요: 당신이 로컬에서 실행하는 명령어는 Git이고, GitHub는 이 명령어들이 도달할 수 있는 여러 대상 중 하나입니다.
Juno원격 저장소란 무엇인가 원격 저장소는 설정에 매핑된 이름으로, origin/main과 같은 원격 추적 브랜치와 쌍을 이루며, 마지막 fetch나 pull 시점에 그 브랜치가 어디에 있었는지를 기록합니다. 자동으로 업데이트되는 것은 없습니다. Git은 요청할 때만 원격 저장소를 확인합니다. GitHub가 실제로 가지고 있는 것과 원격 추적 브랜치가 기억하는 것 사이의 이 간격이 대부분의 fetch-versus-pull 놀라움의 원인입니다.

원격 저장소를 호스팅할 곳: GitHub와 그 외의 선택지

원격 저장소가 하는 모든 것은 순수한 Git이며, 이는 중요한 결과를 가져옵니다: 다른 쪽 끝의 호스트는 바꿀 수 있습니다. Git의 관점에서 모든 호스트는 설정의 URL이며, git push, git pull, git fetch는 모든 호스트에 대해 동일하게 작동합니다. 호스트가 추가하는 것은 한 단계 위에 있습니다: 코드의 웹 보기, 리뷰 흐름, 이슈 추적, 접근 제어입니다. 장단점을 명확히 하면서 현황을 소개합니다:

  • **GitHub**는 단연 가장 크며 오픈소스 작업의 대다수를 호스팅합니다. 강점은 네트워크입니다: 기여하고 싶은 프로젝트들이 이미 여기 있고, 튜토리얼들이 이를 가정하며, 고용주들이 당신의 프로필을 여기서 찾습니다. 트레이드오프는 폐쇄형 플랫폼(Microsoft의 소유)이며, Git 호스팅 이상의 기능에 의존할수록 이 플랫폼에 더 묶이게 됩니다.
  • **GitLab**은 가장 가까운 완전한 대안으로, 약간 다른 이름의 동일한 핵심 기능을 가지고 있습니다 (풀 리퀘스트는 여기서 "merge request"라고 합니다). 돋보이는 점은 자신의 서버에서 실행할 수 있는 자체 관리 버전으로, 코드를 사내에 보관하는 회사들이 이를 많이 선택하는 이유입니다. 트레이드오프는 많은 것을 번들로 제공하며, 플랫폼이 당신이 찾는 코드 호스팅보다 더 무거울 수 있다는 점입니다.
  • **Bitbucket**은 Atlassian의 호스트로, 프로젝트 추적 및 문서 도구인 JiraConfluence 옆에 앉도록 만들어졌습니다. 팀이 이미 이 도구들을 사용하고 있다면 완벽하게 맞아떨어집니다. 이 생태계 밖에서는 세 개 중 가장 작은 커뮤니티를 가지고 있으며 오픈소스 존재감이 거의 없습니다.
  • **Codeberg**는 오픈소스 플랫폼 Forgejo에서 운영되는 오픈소스 프로젝트를 위한 비영리 호스트입니다. 매력은 어떤 회사도 호스트를 소유하지 않으며 플랫폼 자체가 오픈소스라는 것입니다. 트레이드오프는 규모입니다: 더 적은 통합, 작은 커뮤니티, 개인 팀 작업보다는 오픈소스에 집중합니다.
  • 자체 호스팅은 모든 것의 기반입니다: Forgejo 또는 Gitea를 실행합니다. 둘 다 무료이고 오픈소스이거나, GitLab의 자체 관리 버전을 당신이 제어하는 하드웨어에서 실행합니다. 완전한 제어와 프라이버시를 얻을 수 있습니다. 트레이드오프는 이를 계속 실행하는 것이 당신의 책임이 된다는 점입니다.

이 핸드북은 대부분의 오픈소스 작업을 호스팅하고 당신이 먼저 협업할 가능성이 가장 높기 때문에 예시에서 GitHub를 사용합니다. 이 장의 모든 명령어는 다른 호스트로 변경 없이 전송됩니다: URL을 바꾸면 일상적인 루틴은 같습니다. 차이점은 한 단계 위에 있으며, 각 사이트의 작업 검토 및 병합 웹 인터페이스에 있습니다. 이것이 다음 장의 풀 리퀘스트 흐름이 들어오는 곳입니다.

선택이 당신의 것일 때, 거의 항상 Git 기능에 관한 것이 아닙니다. 핵심 기능 세트(호스팅 저장소, 리뷰, 이슈, CI 파이프라인)는 모든 곳에 있기 때문입니다. 내용에 달려 있습니다: 오픈소스에 기여하거나 공개 프로필을 만드는 것은 GitHub를 가리키고, Atlassian 도구를 기반으로 실행되는 회사는 Bitbucket을 가리키며, 코드가 자신의 인프라에만 있어야 하는 경우 GitLab 자체 관리 또는 Forgejo를 가리키고, 가치 중심의 오픈소스 프로젝트는 Codeberg에서 가장 편할 수 있습니다. 선택도 영원하지 않습니다. 호스트 간에 저장소 자체를 이동하는 것은 git remote set-url 하나와 푸시일 뿐입니다. 마이그레이션의 비용이 많이 드는 부분은 Git 위의 계층입니다. 커밋과 함께 여행하지 않는 이슈, 위키, CI 설정입니다.

자체 호스팅은 이를 수행하기 전에 명확하게 봐야 합니다. Forgejo와 Gitea는 작은 서버에서 편하게 실행되지만, 운영 부하는 실제입니다: 보안 업데이트, 저장소와 플랫폼 자체의 데이터베이스의 백업, 계정 및 SSH 키 관리, 가용성, 왜냐하면 다운된 forge는 팀의 모든 push와 pull을 막기 때문입니다. 규정 준수 규칙이 코드를 서드파티 인프라 밖에 두어야 하거나, 에어갭된 환경에서, 또는 조직이 자신의 도구를 자신의 제어 아래에 두고 싶을 때 이를 수행할 가치가 있습니다. 웹 계층 아래의 모든 것은 변하지 않습니다: 이 호스트들 모두 동일한 Git 프로토콜을 말하기 때문에, 당신의 push와 fetch는 이들을 구별할 수 없습니다.

Juno원격 저장소를 호스팅할 곳 GitHub는 대부분의 프로젝트가 있는 곳이며 시작할 때 가장 안전한 기본값이지만, 여러 호스트 중 하나일 뿐입니다: GitLab, Bitbucket, 비영리 Codeberg 모두 동일한 Git 저장소를 저장합니다. Push와 pull은 원격 저장소가 어디에 있든 같은 방식으로 작동하므로, 프로젝트가 다른 곳에 있더라도 여기서 배운 것은 낭비되지 않습니다.
Juno원격 저장소를 호스팅할 곳 호스트는 Git에서 한 계층 위에서 다릅니다: GitLab은 풀 리퀘스트를 merge request라고 부르며 자체 관리 버전을 제공하고, Bitbucket은 Atlassian의 도구에 연결되며, Codeberg는 오픈소스 Forgejo에서 실행됩니다. 협업자와 도구가 이미 있는 곳을 기반으로 선택하고, 나중의 이동은 Git 쪽에서는 저렴하다는 것을 기억하세요. 이슈와 CI는 여행하지 않습니다.
Juno원격 저장소를 호스팅할 곳 원격 저장소가 URL에 매핑된 이름이므로, 호스트 간에 프로젝트를 이동하는 것은 git remote set-url과 하나의 push입니다. Forgejo나 Gitea를 자체 호스팅하면 제어 및 프라이버시를 얻고 패칭, 백업, 가용성이 드는 비용이 들어갑니다. 정책이 요구할 때 그 거래를 취하세요. 재미 때문이 아닙니다. 한 명의 호출기를 담았던 사람입니다. 호스트 특화 모든 것은 Git 프로토콜 위의 웹 계층에 있습니다.

당신의 작업을 보내고 받기: git push와 git pull

원격 저장소가 있으면, 두 개의 명령어로 대부분의 일상 작업이 가능합니다. git push는 로컬 커밋을 원격 저장소로 보냅니다. git pull은 다른 곳에서 만들어진 커밋을 가져와 현재 브랜치에 병합합니다.

bash
$ git push origin main
Enumerating objects: 5, done.
Writing objects: 100% (3/3), 312 bytes | 312.00 KiB/s, done.
To https://github.com/mara-chen/weather-app.git
   9f8e7d6..a1b2c3d  main -> main

origin은 원격 저장소이고, main은 당신이 보내는 브랜치입니다. 마지막 줄이 읽을 가치가 있는 부분입니다: 원격의 main이 한 커밋에서 다음 커밋으로 이동하는 것을 보여줍니다.

당기기는 같은 방식으로, 반대로 작동합니다:

bash
$ git pull origin main
remote: Enumerating objects: 4, done.
Unpacking objects: 100% (4/4), done.
Updating a1b2c3d..b7c9e21
Fast-forward
 src/index.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

이것이 다른 사람과 함께 한 프로젝트에서 일하기 위한 전체 루프입니다: 시작하기 전에 변경된 것을 모두 가져오고, 자신의 작업을 하고 커밋하고, 다시 밀어 올리세요. 다른 사람과 브랜치를 공유할 때마다 밀어 올리기 전에 당겨오세요. 당기기를 건너뛰면 당신의 푸시가 당신이 본 적 없는 커밋 위에 떨어질 수 있으며, Git은 누군가의 작업을 잃을 위험을 무릅쓰기보다는 거부합니다.

처음 새 브랜치를 푸시할 때 -u를 추가합니다 (--set-upstream의 약자):

bash
$ git push -u origin feature/add-forecast-icons
Enumerating objects: 5, done.
Writing objects: 100% (5/5), 412 bytes | 412.00 KiB/s, done.
To https://github.com/mara-chen/weather-app.git
 * [new branch]      feature/add-forecast-icons -> feature/add-forecast-icons
branch 'feature/add-forecast-icons' set up to track 'origin/feature/add-forecast-icons'.

이는 feature/add-forecast-iconsorigin/feature/add-forecast-icons 추적으로 기록합니다. 이 링크를 **업스트림**이라고 합니다. 설정되면 그 이후의 모든 push와 pull은 원격 저장소와 브랜치 이름을 떨어뜨리고 브랜치에서 순수 git push 또는 git pull을 실행할 수 있습니다. 브랜치에 아직 업스트림이 설정되어 있지 않으면 Git이 그렇게 말하고 정확한 명령을 출력하므로, 플래그를 기억해야 할 필요는 거의 없고, 메시지가 나타날 때 인식할 수 있으면 됩니다.

그 업스트림 링크는 -u가 실행되는 순간 저장소의 설정에 기록되는 두 개의 순수 줄로 존재합니다: branch.feature/add-forecast-icons.remote는 원격 저장소를 이름 짓고, branch.feature/add-forecast-icons.merge는 그것의 브랜치를 이름 짓습니다. 이전에 푸시한 브랜치에서 git config --get branch.main.remote를 실행하면 정확히 그 값이 돌아옵니다. 이 두 줄은 또한 git status가 읽는 것입니다. 당신의 브랜치가 origin/main보다 두 커밋 앞에 있거나, 두 것이 떨어져 있다고 말합니다: 비교는 원격 추적 브랜치에 대해 완전히 실행되며, GitHub에서 가져온 것이 없는 로컬 확인입니다. 업스트림을 한 번 설정하면, 그 이후 Git이 보여주는 모든 앞뒤 세기는 동일한 설정 줄 쌍을 읽습니다.

Juno당신의 작업을 보내고 받기git push는 커밋을 원격 저장소로 보내고, git pull은 다른 곳에서 만들어진 커밋을 가져와 당신의 브랜치에 병합합니다. 작업을 시작하기 전에 당겨오고 끝났을 때 밀어 올리면, 프로젝트를 건드리는 다른 누구와도 동기화 상태를 유지합니다. 당기기를 건너뛰는 것이 푸시가 거부되는 가장 일반적인 이유입니다.
Juno당신의 작업을 보내고 받기git push origin main은 커밋을 보내고, git pull origin main은 가져와 병합하며, 일단 브랜치에 git push -u로 업스트림이 설정되면, 두 명령 모두 원격 저장소나 브랜치를 이름 지을 필요 없이 작동합니다. 공유 브랜치에서 푸시 전에 당겨오세요. 그렇지 않으면 원격 저장소가 이미 당신의 로컬 히스토리를 지났기 때문에 푸시가 거부됩니다.
Juno당신의 작업을 보내고 받기git push -u로 설정한 업스트림은 두 설정 줄로, branch.<name>.remotebranch.<name>.merge로 나뉩니다. 플래그가 실행되는 순간 기록됩니다. git status는 동일한 쌍을 읽어 origin/main보다 당신의 브랜치가 얼마나 앞뒤인지 알려주며, 로컬 원격 추적 브랜치에 대해서만 비교합니다. 브랜치당 한 번 설정하고 모든 약자 푸시나 당기기, 모든 앞뒤 세기가 무료입니다.

git fetch 대 git pull

git pull은 두 가지를 한 단계에서 합니다: 원격에서 변경된 사항을 다운로드한 다음 즉시 그 변경 사항을 현재 브랜치에 병합합니다. git fetch는 첫 번째 반만 합니다. 새 커밋을 다운로드하지만 브랜치에 병합하지 않습니다. 현재 브랜치와 작업 파일은 Git을 병합하거나 당기라고 지시할 때까지 정확히 같은 곳에 머물러 있습니다.

거의 모든 사람이 적어도 한 번은 이 함정에 빠집니다: git fetch를 실행하고, 어디든 눈에 띄는 변화를 보지 못하고, 원격에서 아무것도 일어나지 않았다고 가정합니다. 뭔가 일어났습니다: fetch는 아직 당신의 작업 브랜치를 건드리지 않았습니다. 무엇이 내려왔는지 보려면, 이 장의 앞부분의 원격 추적 브랜치를 봅니다: git log origin/main은 원격에 있지만 로컬 main에 도달하지 않은 커밋을 보여줍니다. 이를 가져올 준비가 되면, git merge origin/main이 이를 수행하거나, git pull은 한 명령에서 fetch와 그 병합을 실행합니다.

병합 전에 보기를 원할 때 fetch를 독립적으로 사용합니다. 동료 Priya가 main에 뭔가 푸시했다고 말합니다: git fetch와 그 다음 git log origin/main 또는 git diff main origin/main을 사용하면 로컬 작업 브랜치에 도달하기 전에 정확히 무엇이 변경되었는지 읽을 수 있습니다. 만족하면, git merge origin/main이 이를 가져옵니다. 날마다 대부분의 사람들은 git pull을 바로 사용합니다. 보고 병합하는 것이 한 단계에서 원하는 것이기 때문입니다. Fetch는 공유 브랜치에서 수입 작업을 먼저 읽거나, 병합하기에 지금이 좋은 시점인지 결정하기 전에 자신의 시간을 번다.

Fetch가 실제로 업데이트하는 것은 **refspec**에 의해 결정됩니다: 원격의 어떤 브랜치를 가져올지, 그리고 그것을 저장할 로컬 이름을 Git에 알려주는 원격의 설정에 저장된 매핑입니다. 일반 복제의 기본 refspec은 대략 +refs/heads/*:refs/remotes/origin/*로 읽히며, "원격의 heads 아래 모든 브랜치를 가져와 원격 추적 브랜치에 미러링하고, 그것이 사용한 것을 덮어쓰더라도 이동시키기"를 의미합니다. 이것은 origin/main이 최신 상태로 유지되는 메커니즘 전체입니다: fetch는 원격의 브랜치를 읽고 원격 추적 브랜치를 일치시키도록 다시 쓰고, 멈춥니다. 당신의 자신의 main에 관한 아무것도 별도의 병합, 리베이스, 또는 풀 행동이 fetch가 가져온 것에 작용할 때까지 변하지 않습니다.

Junogit fetch 대 git pullgit pull은 새 커밋을 다운로드하고 한 단계에서 브랜치에 병합합니다. git fetch는 다운로드하고만 원격이 어디에 서 있는지에 대한 Git의 기억을 업데이트합니다. 당신의 브랜치는 당신이 병합할 때까지 머물러 있습니다. fetch 이후 파일에서 눈에 띄는 변화를 보지 못하는 것은 예상된 것입니다. 새 커밋은 원격 추적 브랜치에서 기다리고 있습니다.
Junogit fetch 대 git pullgit fetch는 병합 없이 다운로드하고, git pull은 한 단계에서 다운로드 및 병합합니다. git log origin/main으로 들어오는 커밋을 브랜치에 도달하기 전에 읽기를 원할 때 순수 fetch를 사용하고, 즉시 병합할 준비가 되었을 때 pull을 사용합니다. 이 둘을 섞는 것은 팀에서 가장 흔한 Git 혼동 중 하나입니다.
Junogit fetch 대 git pull Refspec은 정확히 fetch가 무엇을 내려받고 어떤 원격 추적 브랜치를 업데이트할지 결정하며, 기본값은 원격의 heads 아래 모든 브랜치를 미러링합니다. Fetch는 원격 추적 브랜치만 이동하며 절대 체크아웃된 브랜치를 이동하지 않으므로, 병합이나 당기기는 별도의 의도적 단계로 남아 있습니다.

이것이 당신을 어디에 두는지

Push, pull, 그리고 fetch는 커밋을 공유 원격 저장소로 가져가고 다시 가져오는데, 이는 Git의 일상적인 협업에서 필요로 하는 대부분을 다룹니다. 여기의 모든 것은 커밋 루프에 기반합니다: 당신은 여전히 로컬에서 먼저 단계별로 진행하고 커밋하며, 원격 저장소는 그 커밋들이 어디로 여행할 수 있는지만 변경합니다. 다음 부분은 GitHub 자체를 통해 그 협업을 수행하는 것으로, 변경 사항을 제안하고 병합되기 전에 검토를 받는 것입니다. 풀 리퀘스트 흐름은 정확히 그곳을 선택합니다. 이 장의 용어가 여전히 불안정하다면, 원격 추적 브랜치, refspec, 업스트림, 용어집은 각각에 대한 순수 정의를 가지고 있으며, Git이란 무엇인가는 자체적으로 Git-versus-GitHub 구분을 두 번 봐볼 가치가 있습니다.