프로젝트/장기 프로젝트

[트러블슈팅] Git Push 오류 (error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400)

Chipmunks 2024. 10. 8.
728x90

요약

해결방법 1번. http.postBuffer 설정

Git Push 크기가 최대 버퍼 크기보다 크기 때문에 오류 발생합니다.

최대 전송 버퍼 크기는 1.0 MiB 이므로 늘려야 합니다.

# 버퍼 크기를 10 MiB (10 * 1024 * 1024) 로 설정
$ git config http.postBuffer 10485760

$ git push

 

해결방법 2번. 작은 크기로 커밋 푸시

1.0 MiB 를 넘기지 않게 작은 커밋 크기로 푸시합니다.

# 커밋 되돌려 작은 단위로 커밋
$ git reset HEAD^ --soft
...
$ git commit

# 1.0 MiB 를 넘기지 않도록 커밋 푸시
$ git push


해결방법 3번. Remote 연결을 HTTPS가 아닌 SSH로 설정

SSH로 새로 연결해 푸시합니다. (SSH 설정 방법은 본문 참고)

# 기존 origin 삭제
# git remote remove origin

$ git remote add origin git@github.com:xxx/yyy.git

# 테스트 위해 HTTPS와 다른 이름으로 추가
# git remote add origin_ssh git@github.com:xxx/yyy.git

$ git push

 

 

배경

Git 커밋은 되나 GitHub 푸시가 되지 않았습니다.

오류 로그는 아래와 같습니다.

$ git push
오브젝트 나열하는 중: 88, 완료.
오브젝트 개수 세는 중: 100% (88/88), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (67/67), 완료.
error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400
send-pack: unexpected disconnect while reading sideband packet
오브젝트 쓰는 중: 100% (68/68), 2.36 MiB | 2.11 MiB/s, 완료.
Total 68 (delta 43), reused 0 (delta 0), pack-reused 0
fatal: the remote end hung up unexpectedly
Everything up-to-date

 

 

해결 방법

검색 결과 http.postBuffer 설정을 늘려야 한다고 합니다.

$ git config http.postBuffer {maxBytes}

# 버퍼 크기를 3 MiB (3 * 1024 * 1024) 로 설정
# git config http.postBuffer 3145728

$ git push

오브젝트 나열하는 중: 88, 완료.
오브젝트 개수 세는 중: 100% (88/88), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (67/67), 완료.
오브젝트 쓰는 중: 100% (68/68), 2.36 MiB | 3.82 MiB/s, 완료.
Total 68 (delta 43), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (43/43), completed with 17 local objects.

 

약 2.3 MiB 버퍼가 필요하므로 3 MiB 로 설정했습니다.

이후 Git push 명령어가 성공했습니다.

 

분석

git-config docs에서 http.postBuffer 설명을 볼까요?

$ http.postBuffer

Maximum size in bytes of the buffer used by smart HTTP transports when POSTing data to the remote system.
For requests larger than this buffer size, HTTP/1.1 and Transfer-Encoding:
chunked is used to avoid creating a massive pack file locally.
Default is 1 MiB, which is sufficient for most requests.

Note that raising this limit is only effective for disabling chunked transfer encoding and
therefore should be used only where the remote server or
a proxy only supports HTTP/1.0 or is noncompliant with the HTTP standard.
Raising this is not, in general, an effective solution for most push problems,
but can increase memory consumption significantly
since the entire buffer is allocated even for small pushes.

 

눈에 띄는 건 기본값이 1 MiB 라는 점입니다.

다만 1 MiB를 넘을 경우에 HTTP/1.1과 Transfer-Encoding: chunked 으로 전송한다는데...

원격 서버에 해당하는 GitHub 서버가 이를 지원하지 않는가 보네요.

의도한 바는 전송량이 큰 경우 HTTP/1.1 프로토콜로 1 MiB 씩 나눠 전송하는 것 같습니다.

 

다른 브랜치에서 git reset HEAD^ --soft 으로 되돌린 다음

다음 명령어로 Git 네트워크 전송을 디버깅 해보겠습니다.

# 1 MiB 기본값으로 되돌림
$ git config http.postBuffer 1048576

# 커밋을 되돌려서 다른 브랜치에서 테스트
$ git reset HEAD^ --soft
$ git reset HEAD^ --soft
...
$ git branch temp
$ git checkout temp

# CURL Verbose 모드로 실행
$ GIT_CURL_VERBOSE=1 git push
00:29:13.382345 http.c:804              => Send header: POST /xxx/yyy.git/git-receive-pack HTTP/2
00:29:13.382346 http.c:804              => Send header: Host: github.com
00:29:13.382347 http.c:804              => Send header: Authorization: Basic <redacted>
00:29:13.382349 http.c:804              => Send header: User-Agent: git/2.43.0
00:29:13.382350 http.c:804              => Send header: Content-Type: application/x-git-receive-pack-request
00:29:13.382351 http.c:804              => Send header: Accept: application/x-git-receive-pack-result
00:29:13.382353 http.c:804              => Send header: Content-Length: 4

 

POST 요청을 HTTP/2 로 보내는 걸 확인할 수 있습니다.

HTTP/2 에선 Transfer-Encoding: chunked 을 지원하지 않는 걸까요?

RFC9113 문서에서 아래 본문을 찾았습니다.

HTTP/2 uses DATA frames to carry message content.
The chunked transfer encoding defined in Section 7.1 of [HTTP/1.1] cannot be used in HTTP/2;
see Section 8.2.2.

 

HTTP/2 에선 Transfer-Encoding: chunked 을 지원하지 않는다고 나와있네요...!

이는 HTTP/1.1 에서만 사용하고 있습니다.

그러면 Git Curl 버전을 HTTP/1.1 버전으로 강제할 순 없을까요?

 

아래 명령어로 전역적으로 HTTP/1.1 으로 고정시킬 수 있습니다.

$ git config --global http.version HTTP/1.1 # 전역 설정
$ git config --local http.version HTTP/1.1 # 로컬 설정
$ http.version

Use the specified HTTP protocol version when communicating with a server.
If you want to force the default.
The available and default version depend on libcurl.
Currently the possible values of this option are:
- HTTP/2
- HTTP/1.1

 

HTTP/1.1 버전으로 설정한 후에 푸시해보겠습니다.

00:41:46.512607 http.c:804              => Send header: POST /xxx/yyy.git/git-receive-pack HTTP/1.1
00:41:46.512609 http.c:804              => Send header: Host: github.com
00:41:46.512610 http.c:804              => Send header: Authorization: Basic <redacted>
00:41:46.512612 http.c:804              => Send header: User-Agent: git/2.43.0
00:41:46.512613 http.c:804              => Send header: Accept-Encoding: deflate, gzip
00:41:46.512615 http.c:804              => Send header: Content-Type: application/x-git-receive-pack-request
00:41:46.512617 http.c:804              => Send header: Accept: application/x-git-receive-pack-result
00:41:46.512618 http.c:804              => Send header: Accept-Language: ko-KR, *;q=0.9
00:41:46.512620 http.c:804              => Send header: Transfer-Encoding: chunked

...

send-pack: unexpected disconnect while reading sideband packet
오브젝트 쓰는 중: 100% (35/35), 2.57 MiB | 2.40 MiB/s, 완료.
Total 35 (delta 23), reused 0 (delta 0), pack-reused 0
fatal: the remote end hung up unexpectedly
Everything up-to-date

 

HTTP/1.1 POST 요청과 Transfer-Encoding: chunked 헤더를 확인할 수 있습니다만...

여전히 전송은 되지 않습니다.

아무래도 깃허브 프록시 서버가 이를 지원하지 않는 것 같습니다.

 

remote 연결을 HTTPS가 아닌 SSH로 연결한 경우 정상 동작합니다.

SSH로 설정해 Remote 연결합니다.

# ~/.ssh 이동
$ cd ~/
$ mkdir .ssh
$ cd ~/.ssh

# ssh-keygen 으로 RSA 개인키 / 공개키 생성
$ ssh-keygen -t rsa -b 4096 -C "yourgithubemail@domain.com"

# RSA 공개키 복사
$ cat id_rsa.pub

 

깃허브 SSH and GPG keys > Add new SSH Key 에 추가합니다.

(좌) GitHub 계정 설정 > SSH 키 추가 화면 (우) SSH 복사 모달

 

# 기존 origin 삭제
# git remote remove origin

$ git remote add origin git@github.com:xxx/yyy.git

# 테스트 위해 HTTPS와 다른 이름으로 추가
# git remote add origin_ssh git@github.com:xxx/yyy.git

$ git push

 


 

HTTP/1.1로 바꾸면 잘 되나 싶었는데, 뭔가 허무하네요. 😅

GitHub는 물론 GitLab, BitBucket, Gitea 등의 서버마다 다를 수 있으므로

참고 부탁드립니다.

댓글