TechFeedTechFeed
개발자 작업환경

non-fast-forward, git push, rejected | 푸시가 거절되면 뭐부터 볼까?

non-fast-forward 거절은 SSH가 막힌 게 아니라 원격에만 있는 커밋을 지우지 않으려고 깃이 push를 거부한 줄입니다. fetch 다음 rebase로 합치고, 강제 푸시는 force-with-lease만 검토합니다. Git, GitHub, 한국 1인 개발자 기준. 2026년 9월 git push 문서와 GitHub 안내.

by

git push가 non-fast-forward로 거절되면 인증이 실패한 게 아니라, 원격 브랜치에 내 로컬에 없는 커밋이 있어 그 기록을 지우지 않으려고 깃이 밀기를 멈춘 줄입니다. 비밀번호나 SSH 키 문제가 아니라, 이미 접속은 된 뒤의 기록 충돌입니다.

집 맥에서 커밋만 하고 푸시를 깜빡한 채 노트북에서 같은 main을 밀면 이 문장이 나옵니다. 거절 괄호 안이 non-fast-forward인지, 훅 거절인지부터 갈라야 해요.

fetch로 원격 커밋을 본 다음 rebase나 merge로 합치고 다시 밀면 됩니다. 근거는 git push 문서GitHub non-fast-forward 안내에 있습니다.


거절 문장의 괄호부터 읽기

괄호 안이 non-fast-forward면 기록 문제입니다.


터미널에 failed to push some refs만 보이면 원인이 여러 갈래입니다. 그 위 줄을 보면 갈립니다. ! [rejected] main -> main (non-fast-forward)이면 깃이 밀기 전에 거절한 것입니다. git 문서는 이 경우를, 빠르게 앞으로만 가는 갱신이 아니라서 원격 커밋이 지워질 수 있을 때 거절한다고 설명합니다. 힌트는 보통 the tip of your current branch is behind its remote counterpart입니다.


같은 failed to push라도 Permission denied (publickey)는 접속 전에 끊긴 줄입니다. 키를 고치는 절차는 SSH 공개키 글에 따로 있습니다. 이번 글의 문장은 이미 원격과 말이 통한 뒤, 브랜치 끝을 어디로 옮길지에서 멈춘 상태예요. 키를 다시 만들 필요가 없습니다.


한 가지 더, [remote rejected]는 괄호가 다릅니다. 서버의 훅이나 보호 브랜치가 거절한 경우라, 로컬에서 rebase를 해도 같은 훅이 다시 막을 수 있습니다. 괄호를 한 줄만 읽어도 다음에 칠 명령이 달라집니다.


non-fast-forward와 publickey와 remote rejected를 괄호로 나누는 그림
failed to push 한 줄보다 위의 rejected 괄호가 원인을 가른다. 자체 인포그래픽

원격에만 커밋이 생기는 경우

내 로컬이 원격의 끝을 포함하지 않으면 거절됩니다.


빨리감기 푸시는 원격의 최신 커밋이 내 로컬 역사 안에 이미 들어 있을 때만 됩니다. 원격에만 있는 커밋이 있으면, 그냥 밀면 그 커밋이 브랜치 끝에서 사라지므로 깃이 멈춥니다. GitHub 안내도 다른 사람이 같은 브랜치에 밀었거나, 내가 로컬에서 기록을 고친 뒤라고 적습니다.


상황원격에 남는 것먼저 할 일
다른 PC에서 밀고 이 PC는 받기 전그 PC의 커밋fetch 후 pull 또는 rebase
깃허브 웹에서 README 수정웹 커밋 하나fetch 후 합치기
commit --amend 또는 rebase 후고치기 전 커밋의도한 재작성이면 lease로 강제
보호 브랜치 훅서버 규칙괄호가 remote rejected인지 확인

혼자 일해도 노트북과 집 맥이 같은 main을 쓰면 협업과 같은 거절이 납니다. 아침 집 맥에서 커밋만 하고 카페 노트북을 켜면, 노트북의 main은 원격보다 뒤입니다. 그 상태로 새 커밋을 밀면 거절입니다. 풀을 먼저 하지 않아서이지, 저장소 권한이 빠져서이지 않습니다.


fetch 다음에 합치는 순서

밀기 전에 원격에만 있는 커밋 목록을 봅니다.


순서는 고정하는 편이 안전합니다. git fetch origin으로 원격 끝을 가져오고, git status로 지금 브랜치가 뒤인지 갈라졌는지 봅니다. 그다음 git log --oneline --left-right HEAD...origin/main을 치면 왼쪽은 로컬에만, 오른쪽은 원격에만 있는 커밋입니다. 원격 쪽에만 줄이 있으면 받기만 하면 됩니다.


기록을 일부러 다시 쓰지 않았다면 git pull --rebase origin main이 원격 커밋 위에 내 커밋을 다시 올립니다. 충돌이 나면 파일을 고치고 git addgit rebase --continue입니다. 머지 커밋을 남겨도 되면 git pull origin main으로 합쳐도 됩니다. GitHub 문서는 fetch 다음 merge, 또는 pull 한 번으로 둘을 같이 하라고 안내합니다. 끝난 뒤에 git push를 다시 하면 빨리감기가 됩니다.


  • [ ] 괄호가 non-fast-forward인지 확인했다
  • [ ] git fetch origin을 했다
  • [ ] 원격에만 있는 커밋을 log로 봤다
  • [ ] rebase 또는 merge로 합쳤다
  • [ ] 충돌을 끝내고 push를 다시 했다

원격 커밋을 보고 위에 다시 올리기
git fetch origin git status git log --oneline --left-right HEAD...origin/main git pull --rebase origin main git push
fetch로 원격 커밋을 가져온 뒤 rebase하고 push하는 순서 그림
거절된 push를 반복하지 말고, fetch로 원격에만 있는 커밋을 먼저 본다. 자체 인포그래픽

강제 푸시는 언제만 치나

main에 --force를 기본으로 쓰지 않습니다.


git commit --amend나 rebase로 이미 원격에 있던 커밋을 일부러 바꿨다면, 합치기가 아니라 원격 끝을 내 새 커밋으로 바꿔야 합니다. 그때의 명령은 git push --force-with-lease입니다. lease는 내가 fetch로 본 원격 끝과 지금 원격 끝이 같을 때만 덮어씁니다. 그 사이에 다른 PC가 밀었다면 거절하므로, 맹목적인 --force보다 안전합니다.


공유하는 main이나 이미 배포된 브랜치는 강제 푸시하지 않는 쪽이 맞습니다. 다른 노트북이 그 커밋 위에 작업을 올렸다면 그 작업이 브랜치 끝에서 사라집니다. git 문서는 빨리감기가 아닌 갱신을 기본으로 막는 이유가 그 기록 손실이라고 적습니다. 기능 브랜치를 나만 쓰고, 방금 amend한 것이 분명할 때만 lease를 씁니다. 서버에 receive.denyNonFastForwards가 켜져 있으면 강제 푸시도 거절됩니다. 그 경우는 브랜치를 지우고 다시 만드는 편보다, 새 커밋으로 고치는 편이 안전합니다.


force 전에 볼 것 | git log로 원격에만 있는 커밋 제목을 읽으세요. 내가 다른 PC에서 민 작업이면 rebase로 살리고, 방금 amend한 내 커밋뿐이면 lease를 검토하면 됩니다. 제목을 안 읽고 --force부터 치지 않습니다.


노트북과 집 맥이 같은 main일 때

자리를 옮기기 전에 그 PC에서 push까지 끝냅니다.


1인 개발에서도 거절의 절반은 두 기기입니다. 집 맥에서 커밋하고 푸시하지 않은 채 노트북을 켜면, 노트북은 원격이 최신인 줄 압니다. 노트북에서 커밋을 더하면 두 역사가 갈라집니다. 자리를 뜨기 전에 git status로 커밋되지 않은 파일과 푸시되지 않은 커밋을 확인하는 습관이 이 거절을 줄입니다.


이미 갈라진 뒤에는 어느 쪽이 원격에 올라갔는지가 기준입니다. 집 맥 커밋이 원격에 있으면 노트북에서 rebase하면 됩니다. 둘 다 아직 원격에 없고 서로 다르면, 먼저 밀린 쪽을 기준으로 다른 쪽을 합칩니다. 파일 감시 한도나 포트 점유처럼 로컬 프로세스 문제와는 무관합니다. 워처가 터진 증상은 EMFILE 글 쪽이고, 푸시 거절 문장과는 동시에 안 나옵니다.


국내에서 깃허브 웹 에디터로 오타 한 줄을 고친 뒤 로컬 main을 밀다 막히는 경우도 같습니다. 웹 커밋이 원격에만 있는 한 칸입니다. fetch하면 그 한 칸이 보이고, rebase 한 번으로 이어집니다.


거절 힌트를 한글로 옮기면 이렇게 읽힙니다. 지금 브랜치의 끝이 원격보다 뒤에 있으니, 밀기 전에 원격 변경을 합치라는 뜻입니다. 비밀번호를 물어보지 않았다면 접속은 끝난 뒤입니다. 합치기 전에 원격에만 있는 커밋 제목을 소리 내어 읽어 보세요. 어제 집 컴퓨터에서 적은 문장이면 살릴 커밋이고, 방금 고친 내 커밋의 옛 버전이면 덮어쓸 후보입니다. 제목을 모르면 강제 명령은 치지 않습니다. 혼자 저장소를 써도 이 한 줄 확인이 기록을 지킵니다.


집 맥과 노트북이 같은 main에서 커밋이 갈라져 push가 거절되는 그림
두 기기가 같은 브랜치를 쓰면 협업과 같은 non-fast-forward가 난다. 자체 인포그래픽

참고 자료

푸시 거절을 적은 공식 문서만 여기 모아 둡니다.



내부 연계: SSH 공개키 거절, 파일 개수 한도, 도커 소켓 권한


인용한 거절 조건은 2026년 9월 22일 공개 문서 기준입니다.


자주 묻는 질문

거절 문장 앞에서 자주 나오는 질문만 답을 적습니다.


SSH 키를 다시 만들어야 하나요?

non-fast-forward 괄호가 보이면 인증은 이미 통과한 뒤입니다. 키 오류는 Permission denied (publickey)로 그보다 앞에서 끊깁니다. 이번 거절은 fetch로 원격 커밋을 합치면 됩니다.


pull과 pull --rebase 중 무엇을 치나요?

기록을 다시 쓰지 않은 보통의 뒤처짐이면 둘 다 원격 커밋을 가져옵니다. rebase는 내 커밋을 원격 끝 위에 다시 올려 머지 커밋을 남기지 않습니다. 충돌이 나면 rebase --continue로 끝낸 뒤 push합니다.


--force로 바로 밀면 안 되나요?

원격에만 있는 커밋이 브랜치 끝에서 사라집니다. 다른 PC에서 민 작업이면 그 커밋을 잃습니다. 방금 amend한 내 브랜치가 분명할 때만 --force-with-lease를 검토하세요. main의 기본 해법으로 쓰지 않습니다.


remote rejected는 같은 해결인가요?

아닙니다. remote rejected는 서버 훅이나 보호 브랜치가 거절한 줄입니다. 로컬 rebase로 빨리감기를 만들어도 훅이 다시 막을 수 있습니다. 괄호의 단어를 먼저 구분하세요.


혼자 쓰는 저장소인데도 나나요?

납니다. 집 맥과 노트북, 또는 깃허브 웹에서 고친 커밋 하나가 원격에만 있으면 협업과 같은 거절입니다. 자리를 옮기기 전에 push까지 마치면 빈도가 줍니다.


충돌 없이 status만 behind이면요?

로컬 커밋이 없고 원격만 앞선 상태입니다. git pull origin main으로 받아 오면 그 다음 push는 할 일이 없거나, 그 위에 새 커밋을 올린 뒤 밀면 됩니다. 강제 푸시는 필요 없습니다.


push가 거절되면 괄호가 non-fast-forward인지부터 보면 됩니다. fetch로 원격에만 있는 커밋을 확인하고 rebase나 merge로 합친 뒤 다시 밀면 빨리감기가 됩니다. 키 오류와 강제 푸시는 그 다음 문제입니다. 관련 글: SSH 키, EMFILE, 도커 소켓.


non-fast-forwardgit pushrejectedrebaseforce-with-lease깃허브작업환경main개발자

함께 보면 좋은 문제 해결

EXPLORE / 개발자 작업환경

이어서 읽어보기

전체 토픽 둘러보기