위 에러 메시지를 이해하기 위해선 Git의 "upstream"이라는 개념을 알아야 한다.
upstream
은 origin
과 마찬가지로 원격 저장소의 위치를 나타내는 용어이다.
결론부터 말해보자.
origin
은 현재 레포지토리를 기준으로 현재 레포지토리를 받아온 원격 저장소를 의미한다.
그리고 upstream
이란 origin
의 origin
이 되는 원격 저장소를 의미한다.
이미지를 통해 알아보자.
오픈 소스 프로젝트를 Fork 하여 내 Github 계정의 원격 저장소에 저장한 뒤 나의 원격 저장소를 Clone 하여 로컬 저장소를 만들고 싶다고 가정하자.
이런 상황에서 Working Directory가 보기엔 자신에게 코드를 준 내 Github 계정의 원격 저장소는 origin
이 되며 이는 이전에도 설명했다.
이런 상황에서 Working Directory가 보기엔 실제 코드를 다운로드한 오픈 소스 프로젝트는 "원격 저장소의 조상 원격 저장소"라는 의미를 가진다. 하지만 이 오픈 소스 프로젝트를 저장하고 있는 원격 저장소를 "origin의 부모 원격 저장소"로 부르기엔 직관적이지도 않고 불편하다.
따라서 이런 상황을 대비해 원격 저장소의 조상 원격 저장소에 upstream
이라는 이름을 달아준 것이다.
일단 위 에러 메시지를 직독직해 해보자.
fatal : 현재 브랜치인 Main은 upstream Branch를 가지고 있지 않습니다.
"upstream
이 원격 저장소다"라는 개념을 알고 있다면 위 문구가 왜 발생했을지 쉽게 이해할 수 있을 것이다.
"로컬 저장소의 현재 브랜치와 연결되어 있는 원격 저장소 브랜치가 없기 때문"에 해당 에러가 발생한다.
로컬 저장소의 현재 브랜치와 연결되어 있는 원격 저장소 브랜치가 존재하지 않기 때문에 Git 입장에선 로컬 저장소의 커밋을 어느 장소에 Push 해야 할지 알 수 없다.
따라서 Git 입장에선 Push 명령을 받았으나 Push의 목적지를 알 수 없고, 이를 알리기 위해 위와 같은 에러 메시지를 던지는 것이다.
(뇌피셜)
그렇다면 왜origin
이 아닌upstream
으로 에러 문구를 정해놨을까?
대부분의 경우 로컬 저장소에서origin
으로 지정한 원격 저장소에 Git Push를 진행할 텐데 말이다.개인적으로는 Git Pull이나 Push를
origin
뿐만 아니라upstream
에도 수행할 수 있기 때문이라고 생각한다.Git에서는 원격 저장소의 위치에 관계 없이 Pull 받거나 Push 할 수 있기 때문에
upstream
과origin
모두 위와 같은 문제가 발생할 수 있다.
(즉,upstream
에 Push 하려 했는데upstream
쪽에 로컬과 연결되어 있는 브랜치가 존재하지 않을 수 있다)
upstream
과origin
모두 상대적인 위치가 다를 뿐 "원격 저장소"를 나타내는 용어임은 변하지 않으므로 더 상위 저장소인upstream
을 에러 메시지에 포함시킴으로써 더 넓은 범위 개념을 사용해 유사한 에러를 한 번에 처리할 수 있게 한 것이 아닐까 싶다.
위 에러의 해결 방법은 에러 문구에 이어 적혀 있는 문장에 명시되어 있다.
To push the current branch and set the remote as upstream, use git push --set-upstream origin main
즉, 단순히 git push
명령어에 --set-upstream
옵션을 붙여 로컬 브랜치와 원격 브랜치를 연결해 주면 되며 이를 위해 아래와 같은 코드를 입력해 주면 될 것이다.
git push --set-upstream origin main
추가로 --set-upstream
옵션은 -u
이라는 단축 옵션도 가지고 있으므로 둘 중 하나를 활용하면 된다.
위에서 git push --set-upstream origin main
명령어를 입력하라고 했지만, 사실 main
이 고정 입력값은 아니다.
오히려 main
이 아닌 다른 로컬 브랜치에서 작업을 수행하다가 위와 같은 에러가 났다면 main
이 아닌 다른 값을 입력해 줘야 한다.
필수 사항은 아니지만 대부분 로컬 저장소의 브랜치와 해당 브랜치와 연결되어 있는 원격 저장소의 브랜치 이름은 동일하게 하는 것이 암묵적인 룰이다
사실 암묵적인 룰이라기보단 편의성을 위해 이렇게 하는 게 당연한데 만약 연동되어 있는 로컬 브랜치와 원격 브랜치 이름이 다르다면 해당 연결 관계를 파악하는데 추가적인 노력을 기울여야 하므로 매우 비효율적일 것이다.
이런 점을 고려했을 때 사실 --set-upstream
의 제대로 된 사용 방법은 아래와 같을 것이다.
git push --set-upstream origin <로컬 브랜치 이름>
실제로 GUI에서 (원격 저장소에 로컬 저장소 이름을 가진 브랜치가 없을 경우) Git Push를 수행하면 자동으로 "로컬 브랜치와 동일한 이름의 브랜치"가 원격 저장소에 생성된 뒤 Push가 진행됨을 볼 수 있다.