Git ↔ GitHub 데이터 흐름 가이드
로컬 저장소와 원격 저장소 사이를 자유롭게 오가기 위한 명령어 정리
1. 핵심 개념: 로컬과 원격은 다른 저장소
가장 먼저 머릿속에 그려둘 그림은 이거야. 커밋(commit)은 내 컴퓨터에만 저장되고, GitHub에 올리려면 push를 해야 해. 반대로 GitHub에서 바뀐 건 fetch나 pull로 가져와야 하고.
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에 처음 올리기
# 로컬 작업 폴더에서
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️⃣ — 다른 컴퓨터에서 같은 프로젝트를 받아 작업
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가 쌓여있는 상태.
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 가지를 구분해야 해.
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된 다음, 작업 브랜치 깨끗이 정리
# 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은 그 변화를 아직 모르는 상태.
# 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 # 무관한 다른 로컬 브랜치
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 처럼 여러 브랜치가 있는 저장소를 받아오면 갑자기 헷갈리기 시작해. 이 섹션은 그 상황을 처음부터 끝까지 정리한 거야.
origin)에 main · A_branch · B_branch 가 있다고 가정. 모든 시나리오는 이 셋팅에서 출발해.
5-1. clone하면 무슨 일이 일어나나
가장 헷갈리는 지점부터. git clone은 모든 브랜치의 데이터를 받지만, 로컬 브랜치(①)는 기본 브랜치 하나만 만든다. 나머지는 원격 추적 참조(②)로만 존재해.
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 # 위 두 결과 합쳐서 한번에 확인
origin/A_branch 라는 이름으로 이미 받아져 있고, 거기서 checkout만 하면 즉시 작업 가능해. 다시 받을 필요 없음.
5-2. 특정 원격 브랜치로 작업하기
방법은 3가지인데 99%는 첫 번째.
방법 ① — 보통의 clone 후 그냥 checkout (가장 흔함)
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 해야 해.
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
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.
-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(=--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.
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 내용 보기
- 5분 이내 복귀 + 변경이 작음 →
stash - 몇 시간/며칠이 걸릴 듯하거나, 변경이 크고 의미 있음 → 임시 commit (
git commit -m "WIP") 한 다음 나중에git commit --amend나git reset HEAD~로 정리. stash는 잊어버리고 잃기 쉬움.
6. 한눈에 보는 요약
- 올릴 땐
push, 내릴 땐pull, 정찰만fetch - 첫 연결은
remote add+push -u, 첫 복제는clone(둘 중 하나만) - push가 거절되면 원격이 앞서있다는 뜻 →
pull먼저 → 다시push -u와clone은 추적까지 자동으로 걸어줘서 이후엔 그냥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 stash→checkout→ 작업 →checkout복귀 →stash pop.