블로그로 돌아가기

Git 포크 upstream 동기화: 안전한 3가지 방법

2026년 9월 6일

TL;DR: git fetch upstream && git merge upstream/main && git push origin main을 실행하면 포크가 최신 상태가 됩니다. “git sync fork with upstream” 워크플로의 전부가 이 한 줄입니다 — 포크의 원본 프로젝트에서 변경을 가져와 자신의 사본에 밀어 넣는 것. 선형 히스토리를 선호한다면 mergegit rebase upstream/main으로 바꾸고 force-push하세요. 그리고 upstream 리모트를 아예 등록한 적이 없다면 아래 1단계부터 시작하세요 — 그 빠진 리모트가 포크가 “동기화되지 않는” 1등 원인입니다. 나머지 — rebase, GitHub sync 버튼, 밀 수 없는 갈라진 브랜치 — 는 이 세 명령어 위에 얹는 세부 사항입니다.

포크를 upstream과 동기화한다는 건 무슨 뜻일까?

포크는 GitHub에서 남의 저장소를 복제한 여러분의 사본입니다. 원본이 upstream이고, 여러분의 사본이 origin입니다. GitHub 포크는 스스로 갱신되지 않습니다 — 메인테이너가 pull request를 병합해도 여러분의 사본은 어제의 코드 그대로입니다. 포크 동기화란 upstream의 새 커밋을 자신의 포크로 끌어와 브랜치가 프로젝트의 현재 상태와 일치하거나, 최소한 포함하게 만드는 작업입니다.

중요한 이유는 두 가지입니다. 첫째, 기여: 낡은 포크에서 연 pull request는 잡음을 추가로 실어 오며, 메인테이너는 병합 전에 업데이트를 요청할 것입니다. 둘째, 셀프호스팅이나 코드 읽기: 포크를 실제 운영에 쓰거나 그냥 읽는다면, 한 달 낡은 포크는 여러분이 갖지 못한 한 달치 버그 수정입니다.

명령줄에서 포크를 upstream과 동기화하는 방법은?

세 단계입니다: upstream을 한 번 선언하고, fetch한 다음, merge해서 push합니다. 연결은 영구적입니다 — 다음부터는 2단계와 3단계만 입력하면 됩니다.

1단계 — upstream 리모트 추가(클론당 1회).

# 포크의 로컬 클론 안에서
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v   # 확인: origin -> 내 포크, upstream -> 원본

올바른 URL은 원본 저장소 페이지의 초록 Code 버튼에서 찾을 수 있습니다. 흔한 실수는 두 리모트를 모두 자신의 포크로 향하게 하는 것 — 그러면 “sync”가 조용히 아무것도 하지 않습니다. 지금 가진 것만큼 낡은 사본에서 fetch했을 뿐이니까요.

2단계 — upstream 브랜치를 fetch하고 merge.

git checkout main
git fetch upstream
git merge upstream/main
git push origin main

“git sync fork with upstream command line”의 표준 답이 이것입니다. 정상 결과는 fast-forward입니다 — 포크의 main에 새것이 없었다면 그저 upstream/main 앞으로 미끄러질 뿐이고 merge 커밋은 생기지 않습니다.

3단계 — 필요할 때 반복. git fetch upstream && git merge upstream/main && git push origin main 이외에 외울 것은 없습니다. merge 전에 얼마나 뒤처졌는지 보려면 fetch 후 git rev-list --count main..upstream/main을 실행하세요.

포크 동기화 시 rebase와 merge 중 무엇을 써야 할까?

둘 다 같은 코드를 포크에 들여놓습니다. 다른 것은 남겨지는 히스토리입니다. 저장소당 한 정책을 정해 지키세요:

방법명령어히스토리 결과적합한 경우
Mergegit merge upstream/main갈라진 브랜치에 merge 커밋 하나 추가열려 있는 PR이 있는 feature 브랜치 — 절대 아무것도 재작성하지 않음
Rebasegit rebase upstream/main커밋을 위에 재생성, 선형 히스토리포크의 main을 깔끔하게 유지; 리셋하고 싶은 갈라진 포크
GitHub UISync branch 버튼 / PR 병합merge와 동일클론을 열지 않고 빠르게 따라잡기

sync의 rebase 버전:

git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main

force push가 필요한 이유는 rebase가 커밋 ID를 재작성하기 때문입니다 — 포크의 원격 브랜치가 더 이상 로컬 브랜치의 후손이 아닙니다. 항상 --force보다 --force-with-lease를: 누군가(또는 여러분의 다른 기계가) 그사이 push했다면 원격을 덮어쓰기를 거부합니다. 위험한 명령을 기본적으로 안전하게 만들어 주는 장치입니다.

손목에 새기자면: 열려 있는 pull request가 있는 브랜치는 자신이 하고 있는 것을 알 때를 제외하고 절대 rebase하지 마세요 — rebase는 커밋 ID를 바꾸고, 이는 열려 있는 PR을 커밋에서 떼어 놓을 수 있습니다. main 동기화는 merge로 하고(또는 새 작업 시작 전에 rebase), PR 브랜치는 이 일에서 빼 두세요.

포크가 upstream과 동기화되지 않는 이유는?

실제 터미널에서 등장하는 순서대로 늘 그 네 가지 용의자:

  1. upstream 리모트가 없음git remote -vorigin만 보여 줍니다. 증상: git fetch upstream'upstream' does not appear to be a git repository로 실패. 해결: 위의 1단계.
  2. fetch만 하고 merge하지 않음 — fetch는 로컬 저장소의 upstream/main을 갱신할 뿐 작업 브랜치는 건드리지 않습니다. 증상: 성공한 fetch 뒤에도 git log가 낡아 보임. 해결: git merge upstream/main.
  3. 갈라진 히스토리 — 포크의 main에 커밋했는데 upstream도 움직였습니다. git pull이 관련 없는 히스토리라며 불평하거나 강제로 merge합니다. upstream이 이기길 원한다면: git reset --hard upstream/main (로컬 main 전용 커밋을 버립니다 — 먼저 git stash list를 확인하거나 브랜치로 백업할 것; 나쁜 reset이 이미 일어봤다면 복구 경로는 git undo last commit과 같습니다: git reflog가 아직 옛 팁을 알고 있습니다).
  4. rebase 후 push가 non-fast-forward로 거부됨 — rebase했는데 평범하게 push했습니다. 해결: git push --force-with-lease origin main.

다섯 번째, 드문 경우: upstream 저장소가 이름을 바꾸거나 삭제된 것이라 1단계의 URL조차 404가 납니다. GitHub은 이름 바뀐 저장소를 리다이렉트하므로, 확실한 실패는 대개 삭제되었거나 비공개가 되었다는 뜻입니다 — 동기화할 대상이 없는 것이죠.

GitHub 웹사이트에서 포크를 동기화할 수 있을까?

네. 포크 페이지의 브랜치 드롭다운에는 브랜치가 뒤처져 있을 때 Sync fork 버튼이 뜹니다; 클릭 한 번으로 upstream을 끌어옵니다. 그 아래로는 같은 일이 pull request로도 됩니다: upstream/main에서 포크의 main으로 PR을 열고 병합하세요.

버튼의 한계가 CLI로 넘어갈 시점을 알려 줍니다: fast-forward나 merge만 하며 rebase는 하지 않고, 브랜치가 갈라져 있으면 커밋을 버리거나 명령줄을 쓰라며 거부합니다. 기본 브랜치만 동기화합니다. 단순 따라잡기 이상의 모든 일은 위의 세 명령어가 도구입니다.

포크는 얼마나 자주 동기화해야 할까?

정직한 답은 새 작업마다입니다: 신선한 main에서 브랜치를 따면, 여는 어떤 PR도 “3주 전 버전 기반입니다”로 시작하지 않습니다. 활발히 기여하는 포크라면 main을 매일 또는 세션마다 동기화하는 데 몇 초가 듭니다. 읽거나 배포만 하는 포크라면 upstream이 원하는 것을 배포할 때 동기화하세요 — 원본 저장소의 releases 피드를 구독하고 릴리스 시점에 sync하면 됩니다. 동기화가 싸다는 것은 곧 루틴이기 때문입니다. 6개월 뒤처진 포크는 merge가 아니라 수술이 필요한 경우가 많고, “포크 좀 sync해 볼까”가 오후 하나를 삼키는 지점입니다.

치트 시트

# 최초 1회 설정
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git

# 루틴 동기화 (merge 정책)
git fetch upstream && git merge upstream/main && git push origin main

# 루틴 동기화 (rebase 정책, 선형 히스토리)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main

# 얼마나 뒤처져 있나?
git fetch upstream && git rev-list --count main..upstream/main

# 수습 불가능하게 갈라졌을 때 — main을 upstream과 동일하게 (파괴적)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main

루틴 두 줄을 손근육에 심어 두면 갈라진 포크는 고치는 문제가 아니라 읽고 지나가는 신기사로 남습니다. git 관리가 서버까지 이어진다면, 기계의 히스토리를 읽을 수 있게 유지하는 나머지 절반은 the journalctl cheat sheet가 다룹니다.

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

ss vs netstat: Linux 포트 명령어, 무엇을 쓸까

글이 마음에 드셨나요? 제 본업이 바로 이런 일입니다. 저를 고용하세요