같은 저장소에 글을 넣는 창구가 둘이라는 그림. 내 PC는 git push로 올리고 브라우저 글쓰기 화면은 GitHub에 직접 커밋하는데, 브라우저로 한 글자만 고쳐도 내 PC는 그 순간부터 뒤처진 상태가 된다.

·6분 읽기

git push가 거절당했습니다. 제가 창구를 둘로 만들어놨더군요


블로그 첫 글을 지웠습니다. 처음 만들 때 딸려온 예제 글이라 이제 필요가 없었거든요.

지우고, 커밋하고, git push를 눌렀더니 이렇게 나왔습니다.

 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'github.com/...'

거절.

창구가 둘이었습니다

원인을 알고 나니 당연했습니다. 제 블로그는 글을 넣는 길이 두 개입니다.

하나는 제 PC입니다. 파일을 고치고 git push로 올립니다.

다른 하나는 브라우저입니다. 블로그에 글쓰기 화면을 붙여뒀는데, 이건 GitHub에 직접 커밋합니다. 제 PC를 안 거칩니다.

밖에서 휴대폰으로 오타 하나만 고쳐도, 그 순간부터 제 PC는 뒤처진 상태가 됩니다. 그리고 저는 그걸 모르는 채로 며칠 뒤에 git push를 누릅니다.

거절은 고장이 아닙니다

메시지를 끝까지 읽으면 git이 이유를 설명해줍니다.

hint: Updates were rejected because the tip of
hint: your current branch is behind its remote
hint: counterpart. If you want to integrate the
hint: remote changes, use 'git pull' before
hint: pushing again.

“네 브랜치 끝이 원격보다 뒤처져 있다.” 그러니까 원격에는 있는데 제 PC에는 없는 커밋이 있다는 뜻입니다. 제가 브라우저로 쓴 그 글입니다.

git 입장에서는 덮어쓸 수 없으니 멈춘 것입니다. 고장이 아니라 안 잃어버리게 해주는 장치입니다. (fetch first)나 (non-fast-forward)라고 뜨는데, 둘 다 같은 이야기입니다.

pull부터 눌렀더니 이번엔 이겁니다

시키는 대로 git pull을 했습니다.

error: Your local changes to the following files would be
overwritten by merge:
	src/content/blog/first-post.md
Please commit your changes or stash them before you merge.
Aborting

또 막혔습니다. 이번에는 작업하던 게 남아 있어서입니다.

원격에서 받아올 내용이 제가 지금 손대고 있는 파일과 겹치니까, git이 그걸 덮어쓰기 전에 멈췄습니다. 이것도 보호 장치입니다.

여기서 순서가 하나 정리됩니다. 커밋을 먼저 하고 pull합니다. 거꾸로 하면 이 자리에서 막힙니다.

그리고 충돌

커밋하고 다시 pull했더니 이번엔 이런 게 나왔습니다.

CONFLICT (modify/delete):
src/content/blog/first-post.md deleted in HEAD
and modified in 8aa65f9. Version 8aa65f9 of
src/content/blog/first-post.md left in tree.
Automatic merge failed; fix conflicts and then
commit the result.

읽어보면 상황이 그대로 적혀 있습니다. 저는 지웠고, 원격에서는 고쳤습니다. git은 둘 중 뭘 원하는지 모르니까 판단을 저에게 넘깁니다.

git status를 보면 더 짧게 나옵니다.

Unmerged paths:
  (use "git add/rm <file>..." as appropriate
   to mark resolution)
	deleted by us:
	  src/content/blog/first-post.md

deleted by us. 지운 건 제 쪽이라는 표시입니다.

충돌 상황에서 어느 쪽을 고를지 보여주는 그림. 내 PC에서는 파일을 지웠고 브라우저에서는 같은 파일을 고쳤을 때, git status에 deleted by us로 표시된다. 여기서 git add를 치면 지웠던 파일이 되살아나고, git rm을 쳐야 지우는 쪽으로 확정된다.

여기서 헷갈리기 쉬운 게 하나 있습니다. 충돌 났을 때 습관적으로 git add -A를 치면, 지웠던 파일이 도로 살아납니다. 충돌 상태에서는 원격 버전 파일이 폴더에 남아 있거든요. 그걸 통째로 담아버리는 겁니다.

지우는 쪽으로 가려면 add가 아니라 rm입니다.

git rm src/content/blog/first-post.md
git commit --no-edit
git push

--no-edit은 병합 메시지를 그냥 기본값으로 쓰겠다는 뜻입니다. 이번엔 통과했습니다.

--force를 쓰면 안 되는 이유

검색하면 git push --force가 바로 나옵니다. 이걸 누르면 거절이 사라지긴 합니다.

대신 브라우저로 쓴 글이 통째로 없어집니다.

--force는 “원격을 내 PC 상태로 맞춰라”라는 뜻입니다. 그런데 제 PC에는 그 글이 없습니다. 없는 상태로 맞추라고 했으니 지워지는 게 맞습니다.

거절당한 상황은 원격에 내가 모르는 게 있다는 신호입니다. 그 상태에서 --force는 “모르는 걸 지워라”와 같은 말입니다.

순서를 붙여뒀습니다

같은 일을 또 겪을 것 같아 벽에 붙이듯 적어뒀습니다.

# 1. 하던 것부터 저장
git add -A
git commit -m "..."

# 2. 원격 것 받아오기
git pull --no-edit

# 3. 충돌 나면 어느 쪽을 남길지 고르고
git rm <파일>      # 지우는 쪽
git add <파일>     # 남기는 쪽
git commit --no-edit

# 4. 올리기
git push

그리고 습관 하나. 작업을 시작하기 전에 git pull을 먼저 합니다. 특히 브라우저로 글을 쓴 날은요. 3초짜리 습관인데, 이걸 안 해서 반나절을 쓴 셈입니다.

짚고 갈 것

이건 git이 어려워서 생긴 문제가 아닙니다. 같은 저장소에 글을 넣는 창구를 제가 둘로 만들어놓고, 하나만 쓰는 것처럼 굴어서 생긴 문제입니다.

브라우저 글쓰기는 편합니다. 지하철에서 오타를 고칠 수 있는 건 큰 장점이고 계속 쓸 생각입니다. 다만 그걸 붙이는 순간부터 내 PC는 더 이상 유일한 원본이 아니라는 것만 기억하면 됩니다.

거절 메시지가 그걸 알려주려던 거였고요.

참고한 문서


댓글

로그인도 이메일도 필요 없습니다. 이름만 적고 편하게 남겨주세요.