개인 프로젝트에서 네이버 로그인 기능을 구현한 뒤
feature 브랜치를 main에 머지하는 과정에서 다음과 같은 에러를 마주했다.
! [rejected] main -> main (fetch first)
Updates were rejected because the remote contains work that you do not have locally.
혼자 작업하는 저장소인데 왜 이런 에러가 발생했을까?
그리고 이런 상황은 실무에서 문제가 될까?
이번 글에서는 실제로 겪은 Git 흐름 꼬임 사례를 바탕으로,
원인 분석과 실무에서 사용하는 예방 전략까지 정리해본다.
1. 문제 상황 요약
작업 흐름은 대략 다음과 같았다.
- feature/firebase-auth-naver 브랜치에서 작업 완료
- GitHub에서 Pull Request 생성
- GitHub 웹 UI에서 PR을 Merge
- 로컬에서 main 브랜치로 이동
- 다시 머지 및 push 시도
- ❌ fetch first 에러 발생
SourceTree 히스토리를 확인해보니
Merge pull request #2 from feature/firebase-auth-naver
라는 커밋이 이미 GitHub(main)에 먼저 존재하고 있었다.
2. 에러의 정확한 의미
Git 에러 메시지의 핵심은 이 문장이다.
remote contains work that you do not have locally
즉,
- 원격(main)에는 이미 새로운 커밋이 있고
- 로컬(main)은 그 커밋을 모르는 상태
- 그 위에 push를 시도했기 때문에 Git이 이를 차단한 것
이를 구조로 표현하면 다음과 같다.
Remote main: A --- B (PR merge 커밋)
Local main: A --- C (로컬에서 만든 merge 커밋)
이 상태에서 push를 하면
원격 히스토리를 덮어쓸 위험이 있기 때문에 Git은 거부한다.
👉 Git이 문제를 만든 게 아니라, 오히려 히스토리를 보호한 것이다.
3. “이렇게 순서가 꼬이면 실무에서는 안 되는가?”
결론부터 말하면 전혀 아니다.
이 상황은 실무에서도 매우 자주 발생한다.
다만 실무에서는 이를 예방하기 위한 명확한 규칙이 있을 뿐이다.
문제가 되는 경우는 다음과 같다.
- GitHub에서 PR을 머지했는데
- 그 사실을 모른 채
- 로컬 main에서 다시 머지 / push를 시도하는 경우
즉, 도구의 문제가 아니라 워크플로우의 문제다.
4. 실무에서 사용하는 핵심 예방 원칙
원칙 1. PR을 GitHub에서 머지했다면, 로컬에서는 반드시 pull부터 한다
가장 중요한 규칙이다.
GitHub에서 PR Merge
↓
로컬 main checkout
↓
git pull origin main
↓
다음 작업
이 규칙 하나만 지켜도 fetch first 에러의 대부분은 사라진다.
원칙 2. main 브랜치에서는 직접 작업하지 않는다
실무에서 main 브랜치는 거의 항상 읽기 전용에 가깝다.
- ❌ main에서 기능 개발
- ❌ main에서 커밋
- ❌ main에서 직접 merge
항상:
feature/* 브랜치에서 작업
→ PR 생성
→ GitHub에서 merge
→ 로컬 main은 pull만 수행
원칙 3. PR 머지는 한 곳에서만 수행한다
혼자 작업하더라도 다음 중 하나만 선택하는 것이 좋다.
- GitHub UI에서만 PR merge
- 혹은 로컬에서만 merge
👉 두 방식을 동시에 사용하면 히스토리가 쉽게 꼬인다.
5. 개인 프로젝트에서 추천하는 깔끔한 패턴
개인 프로젝트라도 실무 감각을 유지하고 싶다면 다음 패턴이 가장 안정적이다.
- feature 브랜치에서 작업
- push
- GitHub에서 PR 생성
- GitHub에서 merge
- 로컬 main으로 이동
- git pull origin main
- feature 브랜치 삭제
이렇게 하면:
- 히스토리가 예측 가능해지고
- SourceTree 그래프가 깔끔해지며
- 실무와 동일한 Git 사용 감각을 유지할 수 있다.
⚠️ 그렇지만.. 이번 프로젝트에서는 유지할 예정
6. 이번 경험에 대한 정리
이번 상황은 다음과 같이 평가할 수 있다.
- ❌ Git을 잘못 사용한 것이 아니다
- ❌ 실무에서 하면 안 되는 실수도 아니다
- ✅ PR 기반 흐름을 실제로 사용했기 때문에 발생한 자연스러운 상황
- ✅ Git의 히스토리 보호 메커니즘을 이해할 수 있는 좋은 경험
오히려 이런 경험을 통해
“왜 실무에서 pull → 작업 → PR → merge → pull” 흐름을 고집하는지
명확하게 이해하게 된다.
마무리
Git에서 발생하는 대부분의 문제는
명령어를 몰라서가 아니라 흐름을 섞어서 사용했기 때문이다.
PR을 GitHub에서 머지했다면
로컬에서는 merge가 아니라 pull만 한다
이 원칙 하나만 기억해도
혼자 하는 프로젝트든, 팀 프로젝트든 Git으로 인한 스트레스는 크게 줄어든다.