Git ↔ GitHub 데이터 흐름 가이드

로컬 저장소와 원격 저장소 사이를 자유롭게 오가기 위한 명령어 정리

1. 핵심 개념: 로컬과 원격은 다른 저장소

가장 먼저 머릿속에 그려둘 그림은 이거야. 커밋(commit)은 내 컴퓨터에만 저장되고, GitHub에 올리려면 push를 해야 해. 반대로 GitHub에서 바뀐 건 fetchpull로 가져와야 하고.

내 컴퓨터 (Local) Working Dir 작업 폴더 .py / .js / .md ... Staging 올릴 준비 영역 git add 후 대기 Local Repo .git 폴더 커밋 히스토리 Remote Repo GitHub origin add commit push ▶ ◀ fetch / pull push = 올리기 · fetch = 정찰 · pull = fetch + merge (가져와서 합치기)
로컬은 3단계(Working / Staging / Repo)로 나뉘고, 그 다음이 GitHub 원격이다.

2. 명령어 분류표

A. 원격 "주소(연결)" 관리 — 보통 한 번만

명령어 언제 쓰나
git remote add origin <주소> 로컬에서 시작한 프로젝트를 GitHub에 처음 연결할 때. origin은 별명(관례).
git remote -v 현재 어떤 원격이 연결돼 있는지 확인.
git remote set-url origin <주소> 연결된 주소를 바꿀 때.

B. 로컬 → 원격 (올리기)

명령어 언제 쓰나
git push -u origin main 첫 push. -u는 "이 로컬 main은 origin/main을 따라감"이라는 추적 설정. 한 번만.
git push 두 번째부터. -u로 추적이 걸려있으면 그냥 push만.

C. 원격 → 로컬 (내려받기)

명령어 언제 쓰나
git clone <주소> GitHub 저장소를 처음 통째로 받아올 때. 폴더가 새로 생김.
git fetch 원격 변경사항을 확인만. 작업 파일 안 바뀜. "정찰" 느낌.
git pull fetch + merge. 가져와서 내 브랜치에 합쳐버림.
git pull --no-edit 자동 merge 시 commit 메시지를 묻는데 그걸 기본값으로 자동 처리.

D. pull 동작 방식 설정

명령어 의미
git config pull.rebase false pull = fetch + merge (기본). 합쳐질 때 merge commit 생김.
git config pull.rebase true pull = fetch + rebase. 내 커밋을 원격 위로 다시 쌓음. 히스토리 깔끔.
git config pull.ff only fast-forward만 허용. 충돌 가능성 있으면 pull 거부. 가장 안전.
💡 초보 추천
pull.rebase false(merge 방식)로 두자. 충돌이 나도 흐름을 이해하기 쉽다.

3. 시나리오별 사용법

시나리오 1️⃣ — 로컬에서 만든 프로젝트를 GitHub에 처음 올리기

로컬 폴더 (init) Local Repo GitHub 빈 저장소 연결 + push add+commit remote add push -u
# 로컬 작업 폴더에서
git init
git add .
git commit -m "first commit"

# GitHub에서 빈 저장소 만들고 주소 복사 → 연결
git remote add origin https://github.com/내이름/프로젝트.git
git remote -v                       # 연결 확인

git push -u origin main             # 첫 푸시 (-u로 추적 설정)

이후로는 git add → commit → git push 만 반복하면 끝.

시나리오 2️⃣ — 다른 컴퓨터에서 같은 프로젝트를 받아 작업

GitHub 저장소 새 PC의 로컬 폴더 작업 → push clone edit
git clone https://github.com/내이름/프로젝트.git
cd 프로젝트
# 작업 → add → commit → push

clone하면 origin 연결과 추적까지 자동 설정돼서 이후엔 push/pull만 쓰면 됨.

시나리오 3️⃣ — GitHub 웹에서 직접 수정한 게 있는 상태

예: 웹에서 README를 고쳤거나, 다른 PC에서 push했거나.

git fetch                # 원격에 뭐 바뀌었는지 정찰만
git log origin/main      # 원격 최신 커밋 확인
git pull                 # 가져와서 합치기

지금 내 작업도 안 했고 충돌도 없으면 pull이 그냥 끝남(fast-forward).

시나리오 4️⃣ — 로컬과 원격 둘 다 따로 커밋이 쌓였을 때 (가장 헷갈리는 상황)

내 PC에서 커밋 A를 했고, 동시에 GitHub에는 커밋 B가 쌓여있는 상태.

공통 조상 A 내 로컬 커밋 B GitHub 커밋 M merge 커밋 git pull git push GitHub 최신화
git push                 ❌ 거절됨 ("rejected, non-fast-forward")

GitHub가 "네 로컬은 원격 최신 상태가 아니야"라고 막음.

해결:

git pull                 # 원격 변경(B)을 내려받아 내 변경(A)과 merge
# (필요시 충돌 해결 → add → commit)
git push                 # 그 다음 push

git config pull.rebase false로 돼 있으면 자동 merge 커밋이 생김. 메시지 묻는 게 귀찮으면 git pull --no-edit.

예시
이 저장소의 최근 커밋 9bef9ce 충돌 해결 완료가 정확히 이 시나리오의 결과물이야.

시나리오 5️⃣ — 원격은 그대로 두고 내가 뭐 바꿨는지만 확인

git fetch
git status                       # "your branch is behind/ahead by N commits"
git diff main origin/main        # 내 main vs 원격 main 차이

fetch는 절대 내 파일을 덮어쓰지 않아서 안전한 정찰용으로 좋음.

4. 브랜치 보기와 정리 (삭제)

브랜치는 3 군데에 따로 살아 있어. 어디 있는 것을 지우는지 헷갈리지 않으려면 먼저 이 3 가지를 구분해야 해.

내 컴퓨터 (Local) ① 로컬 브랜치 .git/refs/heads/ • main • coworkServer * • design * = 현재 작업 중 ② 원격 추적 참조 .git/refs/remotes/origin/ • origin/main • origin/coworkServer 마지막 fetch 시점의 원격 상태 스냅샷 (캐시) ③ 원격 실제 브랜치 GitHub 서버 • main • coworkServer 진짜 데이터는 여기 있음 push push fetch
"브랜치를 지운다"고 할 때 ①·②·③ 중 어느 걸 지우는지에 따라 명령이 다르다.

4-1. 보기 명령

명령어 보여주는 것
git branch ① 로컬 브랜치 목록만 (현재 브랜치는 * 표시)
git branch -vv ① 로컬 + 각 브랜치의 upstream(연결된 ②) + 최근 커밋 한 줄. 가장 자주 쓰는 명령.
git branch -r ② 원격 추적 참조만 (예: origin/main)
git branch -a ① + ② 전부
git remote show origin ③ GitHub의 진짜 브랜치 + 추적 매핑까지 자세히
# 출력 예시 — git branch -vv
* coworkServer  7dd9ec4 [origin/coworkServer] peer 목록 부트스트랩...
  design        b27efe4                       # 대괄호 없음 = upstream 없음
  main          f46d979 [origin/main]         스케줄 바 우측 상태 적용
[origin/coworkServer] 처럼 대괄호로 표시되는 것이 upstream(추적). 이게 없으면 그 브랜치는 로컬 전용이고 push된 적이 없다는 뜻.

4-2. 삭제 명령 — 3 가지 케이스

대상 명령어 영향 범위
① 로컬 브랜치 git branch -d <이름>
git branch -D <이름>
-d안전 모드(merge 안 됐으면 거부). -D강제 삭제. 원격은 그대로 남음.
③ 원격 브랜치 git push origin --delete <이름> GitHub 측 브랜치까지 사라짐. 되돌리기 어렵다 — 신중히.
② 캐시 정리 git fetch --prune GitHub에서는 이미 지워졌는데 로컬 origin/foo 캐시만 남아있을 때 청소.
주의
현재 체크아웃 중인 브랜치는 못 지움. 다른 브랜치로 이동 후 시도해야 함.
git checkout main → 그 다음 git branch -d 다른브랜치.

시나리오 6️⃣ — PR이 main에 merge된 다음, 작업 브랜치 깨끗이 정리

시작 상태 로컬 main (옛날) PR이 GitHub에서 merge됨 git pull 로컬 main (최신) merge된 내용 받음 branch -d 로컬 feature 삭제 ① 정리 완료 선택 — 원격도 정리 GitHub feature 아직 남아있음 push --delete GitHub에서도 삭제 fetch --prune origin/feature 캐시도 청소 (②)
# PR이 GitHub에서 merge된 직후

git checkout main
git pull                              # merge된 내용 로컬로 가져옴

git branch -d coworkServer            # ① 로컬 작업 브랜치 정리
git push origin --delete coworkServer # ③ GitHub 브랜치도 정리 (선택)
git fetch --prune                     # ② 캐시 정리 — push --delete 했다면 보통 자동
한 번 설정해두면 편함
git config --global fetch.prune true 하면 매 fetch/pull 마다 ②가 자동 청소돼서 신경 안 써도 됨.

시나리오 7️⃣ — -d가 거부될 때 ("not fully merged")

merge 안 된 작업이 있는 브랜치를 지우려고 하면 git이 막아.

git branch -d design
error: The branch 'design' is not fully merged.
If you are sure you want to delete it, run 'git branch -D design'.

두 가지 길이 있어:

  • 아직 의미 있는 작업이면 → 지우지 말고 PR을 만들거나 다른 브랜치에 merge하기
  • 버려도 되는 실험이면git branch -D design 으로 강제 삭제
위험
-D되돌리기 매우 어려움 — 그 브랜치에만 있던 커밋은 사라지고, git reflog에 한동안 남아있긴 하지만 시간이 지나면 GC가 정리해버려.

시나리오 8️⃣ — GitHub 웹에서 PR merge + Delete branch 한 뒤 로컬 정리

가장 흔한 협업 흐름. GitHub 사이트에서 PR을 만들고 "Merge pull request" 버튼 + "Delete branch" 버튼까지 누른 직후, 로컬 git은 그 변화를 아직 모르는 상태.

GitHub 측 (이미 일어난 일) main + coworkServer PR 생성 직전 Merge PR main (작업 합쳐짐) + coworkServer Delete branch main 만 남음 ③ coworkServer 사라짐 로컬에서 해야 할 일 (3 단계) 1. fetch --prune ② origin/coworkServer 캐시 정리 + main 갱신 정찰 2. checkout main & pull 로컬 main 에 merge commit 받아옴 (① 갱신) 3. branch -d 로컬 작업 브랜치 삭제 (① 정리 완료)
# 1) 원격 변화를 정찰 + 사라진 브랜치의 캐시 청소
git fetch --prune

# 출력 예 — origin/coworkServer 가 사라졌음을 알려줌
#  - [deleted]      (none)     -> origin/coworkServer
#    f46d979..3ca4fa2  main     -> origin/main

# 2) main 으로 이동해서 merge 결과 받아오기
git checkout main
git pull

# 3) 로컬 작업 브랜치 삭제 (이미 merge됐으니 -d 가 안전 통과)
git branch -d coworkServer

완료 후 git branch -vv 결과:

* main    3ca4fa2 [origin/main] Merge pull request #1...
  design  b27efe4                                     # 무관한 다른 로컬 브랜치
왜 시나리오 6 과 다른가
시나리오 6은 로컬 CLI에서 원격 브랜치까지 지우는 흐름(push --delete). 이 시나리오는 GitHub 웹에서 이미 지운 후이므로 push --delete 가 불필요(쓰면 "remote ref does not exist" 오류). 대신 fetch --prune 으로 캐시 정리.
주의
그냥 git pull 만 해도 되는 거 아닌가? — 됨. 그러면 main 갱신 + prune 도 같이 일어나(설정에 따라). 다만 현재 브랜치가 coworkServer인 채로 pull 하면 사라진 upstream 때문에 에러가 나. 그래서 fetch --prune 먼저 → checkout main → pull 순이 안전.

5. 여러 브랜치 다루기 (협업 시작점)

혼자 쓸 때는 main 하나만 보다가, GitHub에 A_branch·B_branch 처럼 여러 브랜치가 있는 저장소를 받아오면 갑자기 헷갈리기 시작해. 이 섹션은 그 상황을 처음부터 끝까지 정리한 거야.

전제 상황
GitHub 저장소(origin)에 main · A_branch · B_branch 가 있다고 가정. 모든 시나리오는 이 셋팅에서 출발해.

5-1. clone하면 무슨 일이 일어나나

가장 헷갈리는 지점부터. git clone모든 브랜치의 데이터를 받지만, 로컬 브랜치(①)는 기본 브랜치 하나만 만든다. 나머지는 원격 추적 참조(②)로만 존재해.

GitHub (origin) • main • A_branch • B_branch 3개 브랜치 모두 존재 (객체 데이터 전부) git clone 내 컴퓨터 (Local) — clone 직후 ① 로컬 브랜치 .git/refs/heads/ • main * main 하나만 자동 생성됨. A_branch · B_branch 는 아직 작업본이 없음. ② 원격 추적 참조 .git/refs/remotes/origin/ • origin/main • origin/A_branch • origin/B_branch 3개 전부 받아옴 — 단, "참조"일 뿐 체크아웃 X checkout 시점에 ②에서 ①로 복사됨 →
clone은 객체는 모두 받지만 로컬 작업 브랜치는 main 하나만 만든다.
git clone https://github.com/내이름/프로젝트.git
cd 프로젝트
git branch                 # * main  ← 로컬은 main 하나뿐
git branch -r              # origin/main, origin/A_branch, origin/B_branch ← 원격은 다 보임
git branch -a              # 위 두 결과 합쳐서 한번에 확인
💡 핵심
"GitHub에 있는 A_branch 가 내 로컬에 보이지 않는다"는 착각은 흔해. 사실은 origin/A_branch 라는 이름으로 이미 받아져 있고, 거기서 checkout만 하면 즉시 작업 가능해. 다시 받을 필요 없음.

5-2. 특정 원격 브랜치로 작업하기

방법은 3가지인데 99%는 첫 번째.

방법 ① — 보통의 clone 후 그냥 checkout (가장 흔함)

checkout 전 ① 로컬 브랜치 • main * ② 원격 추적 • origin/main • origin/A_branch • origin/B_branch git checkout A_branch checkout 후 ① 로컬 브랜치 • main • A_branch * (생성) ② 원격 추적 • origin/main • origin/A_branch ←┐ • origin/B_branch │ ↑ 로컬 A_branch ↔ origin/A_branch 자동 추적(upstream) 설정
기존 원격 브랜치 이름으로 checkout 하면 로컬 브랜치가 자동 생성되고 추적까지 걸린다.
git clone https://github.com/내이름/프로젝트.git
cd 프로젝트

git checkout A_branch        # 신버전: git switch A_branch
# 출력: "Switched to a new branch 'A_branch'"
#       "Branch 'A_branch' set up to track 'origin/A_branch'"

git branch -vv               # [origin/A_branch] 추적 확인

방법 ② — clone할 때부터 기본 브랜치를 지정

git clone --branch A_branch https://github.com/내이름/프로젝트.git
# 모든 브랜치 객체는 받지만, 처음 체크아웃이 A_branch가 됨

방법 ③ — 그 브랜치만 받기 (용량 절약)

git clone --single-branch --branch A_branch https://github.com/내이름/프로젝트.git
# origin/B_branch 등 다른 브랜치는 안 받음. 나중에 보고 싶으면:
git remote set-branches origin '*'
git fetch
주의
--single-branch는 대형 모노레포에서 디스크/네트워크를 아끼려는 게 아니면 굳이 쓸 필요 없음. 평범한 프로젝트는 그냥 방법 ①.

5-3. 브랜치별 pull

핵심 규칙: git pull지금 체크아웃된 브랜치 하나만 갱신한다. A_branch와 B_branch를 둘 다 최신으로 만들고 싶으면 각각 들어가서 두 번 pull 해야 해.

현재 체크아웃: A_branch 로컬: A_branch (오래된 상태) 원격(origin/A_branch): 2 commits ahead git pull → A_branch 갱신 → B_branch 안 건드림 → main 안 건드림 결과: 로컬 A_branch가 원격과 같아짐 (B_branch / main은 옛날 그대로) 그 다음: checkout B_branch → pull 로컬: B_branch (오래된 상태) 원격(origin/B_branch): 1 commit ahead git pull → B_branch만 갱신됨 결과: B_branch도 최신화 완료
pull은 현재 브랜치 1개에만 영향. 모든 브랜치 갱신 = "checkout → pull" 반복.
# 둘 다 최신으로 만들기
git checkout A_branch
git pull                         # origin/A_branch → A_branch

git checkout B_branch
git pull                         # origin/B_branch → B_branch
팁 — fetch는 한 방에 다 갱신
만약 "로컬 브랜치들은 일단 그대로 두고, 원격에서 뭐가 바뀌었는지 정찰만" 하고 싶으면:
git fetch                        # origin/* 전부 한꺼번에 갱신
git log A_branch..origin/A_branch  # 차이 보기
git log B_branch..origin/B_branch
그런 다음 필요한 브랜치만 골라 checkout → merge/pull 하면 됨.
함정
git pull origin B_branch 처럼 다른 브랜치 이름을 명시하면 git은 "지금 체크아웃된 브랜치에 B_branch를 머지"하라는 뜻으로 해석함. A_branch에 있는데 저 명령을 치면 A_branch에 B_branch 내용이 합쳐져 버려. 의도와 거의 항상 다름.

브랜치별로 pull하려면 반드시 먼저 checkout.

5-4. 새 로컬 브랜치 → 새 원격 브랜치 (협업 시작점)

가장 자주 묻는 흐름. 로컬에서 C_branch_local 만들어 작업 → GitHub에 같은 이름의 브랜치로 push.

① 시작 (main 체크아웃) ② checkout -b C_branch_local ③ 작업 + commit ④ push -u Local • main * main 커밋들 GitHub • main • A_branch · B_branch Local • main • C_branch_local * 새 가지는 같은 자리에서 시작 GitHub (변화 없음) • main • A_branch · B_branch Local • main • C_branch_local * 새 커밋 2개 (로컬에만) GitHub (아직 모름) • main • A_branch · B_branch Local • main • C_branch_local * ↕ 추적(upstream) ↔ origin/C_branch_local GitHub (갱신됨) • main · A · B • C_branch_local (new) ───────────────────── 네 단계 ───────────────────── checkout -b (분기 생성) → add & commit (작업 저장) → push -u (원격 생성 + 추적 연결)
로컬에 새 가지를 만들고 → 작업하고 → -u 옵션으로 첫 push 하면 원격에 같은 이름의 가지가 새로 생긴다.
# 0) 시작은 어떤 브랜치든 상관없음 (보통 main)
git checkout main
git pull                              # main 최신화 (선택)

# 1) 새 브랜치 만들고 그 위로 이동 (한 번에)
git checkout -b C_branch_local        # 신버전: git switch -c C_branch_local
# 출력: "Switched to a new branch 'C_branch_local'"

# 2) 작업 → add → commit (평소처럼)
git add .
git commit -m "C 브랜치 작업 시작"

# 3) 첫 push — -u 옵션 잊지 말 것
git push -u origin C_branch_local
# GitHub에 'C_branch_local' 브랜치가 새로 만들어지고
# 로컬 C_branch_local ↔ origin/C_branch_local 추적까지 자동 연결됨

# 4) 이후엔 그냥
git push
git pull
왜 -u 가 핵심인가
-u(=--set-upstream) 없이 git push origin C_branch_local 만 해도 원격에 브랜치는 생기지만, 추적은 안 걸려서 다음번에 git push(인자 없이) / git pull(인자 없이) 가 안 됨. 매번 브랜치 이름을 적어야 함. 처음 한 번만 -u 붙이면 평생 편함.
잘 하는 실수
git push -u origin main 처럼 다른 사람도 쓰는 main 브랜치에 -u를 다시 거는 건 의미 없고 혼동만 생김. -u그 브랜치의 첫 push에만.

5-5. 로컬·원격 이름이 다를 때

로컬에선 C_branch_local 인데 GitHub엔 C_branch_github 로 올리고 싶다면 로컬:원격 표기를 쓴다.

# 첫 push에서 이름 매핑
git push -u origin C_branch_local:C_branch_github

# 결과:
#   로컬:  C_branch_local *
#   원격:  C_branch_github  ← 추적
#   git branch -vv → C_branch_local [origin/C_branch_github]

# 이후엔 그냥 push/pull (추적 덕에 알아서 매핑)
git push
git pull
권장하지 않음
이름이 다르면 git branch -vv · GitHub UI · PR 화면이 매번 헷갈림. 정말 필요한 게 아니면 로컬·원격 이름을 같게 두자.

이미 push된 다음에 이름 바꾸기

# 1) 로컬 브랜치 이름 변경
git branch -m C_branch_local C_branch_new

# 2) 원격에 새 이름으로 push
git push -u origin C_branch_new

# 3) 옛 원격 브랜치 삭제
git push origin --delete C_branch_local

5-6. 작업 중 다른 브랜치로 잠깐 (stash)

C_branch_local 에서 작업 중인데 — 아직 commit하긴 어색하고 — 갑자기 main 의 급한 버그를 봐야 한다. 그냥 checkout main 하면 git이 막거나 작업이 따라와 버려. 이럴 때 stash.

C_branch_local * edited: foo.py edited: bar.py (uncommitted) 작업 중인 변경사항 stash 📦 stash 스택 stash@{0} ← 방금 작업 디렉토리는 깨끗 → checkout 자유 checkout main main * 긴급 수정 작업 → commit → push main은 깨끗했으니 자유롭게 작업 가능 checkout C stash pop C_branch_local * edited: foo.py edited: bar.py 하던 작업 복원 ✓
stash는 작업 중인 변경을 임시 보관함에 밀어넣고 작업 디렉토리를 깨끗하게 만든다. 나중에 pop으로 꺼냄.
# 1) 작업 중 변경을 임시 보관
git stash                          # 또는 git stash push -m "C 작업 도중"
git status                         # "nothing to commit, working tree clean"

# 2) 자유롭게 다른 브랜치로 이동, 작업, commit, push
git checkout main
# 긴급 수정 → add → commit → push

# 3) 돌아와서 보관함에서 꺼내 다시 적용
git checkout C_branch_local
git stash pop                      # 마지막 stash 적용 + 스택에서 제거
# 또는 git stash apply  ← 적용만 (스택에는 남음)

# 보관함 확인
git stash list                     # stash@{0}, stash@{1}, ...
git stash show -p stash@{0}        # 특정 stash 내용 보기
언제 stash 대신 commit?
  • 5분 이내 복귀 + 변경이 작음 → stash
  • 몇 시간/며칠이 걸릴 듯하거나, 변경이 크고 의미 있음 → 임시 commit (git commit -m "WIP") 한 다음 나중에 git commit --amendgit reset HEAD~ 로 정리. stash는 잊어버리고 잃기 쉬움.

6. 한눈에 보는 요약

  • 올릴 땐 push, 내릴 땐 pull, 정찰만 fetch
  • 첫 연결remote add + push -u, 첫 복제clone (둘 중 하나만)
  • push가 거절되면 원격이 앞서있다는 뜻 → pull 먼저 → 다시 push
  • -uclone은 추적까지 자동으로 걸어줘서 이후엔 그냥 push/pull
  • 충돌이 무서우면 git config pull.rebase false + git pull --no-edit 조합으로 시작
  • 브랜치는 3 군데에 따로 있음 — ① 로컬 / ② origin/X 캐시 / ③ GitHub 실제. 지우는 명령이 각각 다름.
  • 로컬 정리 git branch -d · 원격 정리 git push origin --delete · 캐시 정리 git fetch --prune
  • clone은 객체는 다 받지만 로컬 브랜치는 기본 브랜치 하나만 만든다. git checkout A_branch 로 그때그때 만들어 쓰면 됨.
  • git pull지금 체크아웃된 브랜치 하나만 갱신. A·B 둘 다 받으려면 checkout 두 번.
  • 새 브랜치를 원격에 처음 올릴 땐 git push -u origin <브랜치>-u가 추적까지 걸어줌.
  • 로컬 작업 중 다른 브랜치로 잠깐 옮길 땐 git stashcheckout → 작업 → checkout 복귀 → stash pop.
Project Planner · Git ↔ GitHub 가이드 · 2026-05-08