大容量Gitリポジトリのcloneで通信エラーが出たときの対処法
目次
こんにちは。金澤です。
今回は、大容量のGitリポジトリをローカル環境にcloneしようとした際に発生したエラーと、その対応についてまとめます。普段の開発では何気なく「git clone」を実行することが多いですが、リポジトリの容量が大きい場合や、取得対象のオブジェクト数が多い場合、途中で通信が切れてcloneに失敗することがあります。
発生した事象
新規リポジトリをローカル環境にcloneするため、最初は通常通り「git clone」を実行しました。コマンドは以下のような形です。
git clone https://example.com/git/PROJECT/repository.git C:\work\repository
通常であれば、このコマンドを実行することで指定したディレクトリにリポジトリが作成されます。しかし、今回はcloneの途中で以下のようなエラーが発生しました。
Cloning into 'C:\work\repository'... remote: Enumerating objects: 14218, done. error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0 fetch-pack: unexpected disconnect while reading sideband packet fatal: protocol error: bad pack header
また、以下のようにHTTP/2に関するエラーも発生しました。
error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: INTERNAL_ERROR (err 2) fetch-pack: unexpected disconnect while reading sideband packet fatal: protocol error: bad pack header
この時点では、「リポジトリの容量が大きすぎることが原因なのか」「通信方式の問題なのか」は断定できない状態でした。ただし、取得対象のオブジェクト数が多く、取得中に通信が切断されていることはログから確認できました。
最初に確認したこと
まず、clone先のURL自体が正しいかを確認しました。cloneに失敗した場合、最初から容量やGitの設定を疑うのではなく、まずはリモートリポジトリに接続できるかを確認することが大切です。
接続確認には、以下のコマンドを使用しました。
git ls-remote https://example.com/git/PROJECT/repository.git
このコマンドは、リモートリポジトリの参照情報を取得するためのものです。実行した結果、以下のように「HEAD」や「refs/heads/main」が表示されたため、URLや認証については大きな問題がないことが確認できました。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx HEAD xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx refs/heads/main
つまり、リポジトリ自体にアクセスできないわけではなく、clone処理の途中でデータ取得に失敗している状態だと考えました。
HTTP/1.1への変更
エラーメッセージの中に、以下の内容が含まれていました。
curl 92 HTTP/2 stream 5 was not closed cleanly
このメッセージから、HTTP/2の通信に起因する可能性が考えられたため、HTTP/1.1を使用するように設定しました。
git config --global http.version HTTP/1.1
この設定は、GitがHTTP通信を行う際にHTTP/1.1を使用するようにするものです。ただし、この設定だけでリポジトリの容量が減るわけではありません。
HTTP/1.1への変更は、あくまでHTTP/2に関する通信エラーを回避するための対処です。そのため、通信方式の見直しとあわせて、取得する履歴量を制限する対応も行いました。
shallow cloneで取得量を制限する
次に試したのが、「–depth」を指定したshallow cloneです。shallow cloneとは、Gitの履歴をすべて取得するのではなく、指定した深さまでの履歴だけを取得する方法です。例えば、以下のコマンドでは最新から50コミット分の履歴を取得します。
git clone --depth=50 https://example.com/git/PROJECT/repository.git C:\work\repository
このコマンドを実行した結果、通常のcloneでは失敗していたリポジトリを取得することができました。実行結果は以下のようになりました。
Cloning into 'C:\work\repository'... remote: Enumerating objects: 5316, done. remote: Counting objects: 100% (5316/5316), done. remote: Compressing objects: 100% (2626/2626), done. Receiving objects: 100% (5316/5316), 1.81 GiB, done. Resolving deltas: 100% (3108/3108), done. Updating files: 100% (4049/4049), done.
通常cloneでは14218件のオブジェクトを取得しようとして失敗していました。一方で、「–depth=50」を指定した場合は、取得対象が5316件となり、cloneに成功しました。
この結果から、取得対象を減らすことで、通信断を回避できる可能性があることがわかりました。
cloneとfetchの違い
今回の対応では、最初に「git clone」を実行し、clone後の不足している履歴を取得するために「git fetch」を使用しました。「git clone」は、リモートリポジトリを初めてローカル環境に作成するためのコマンドです。
一方で、「git fetch」は、すでにローカルに存在するリポジトリに対して、リモートの情報や履歴を追加取得するためのコマンドです。今回の場合、「git clone –depth=50」によってローカルにリポジトリ自体は作成できています。そのため、残りの履歴を追加取得する段階では、「git clone」ではなく「git fetch」を使用しました。
履歴を段階的に追加取得する
「git clone –depth=50」でリポジトリ自体は取得できましたが、全量は取得できていない状態です。そこで全履歴を一括で取得する「git fetch –unshallow」を試してみます。
cd C:\work\repository git fetch --unshallow
しかし、以下のようなエラーが発生しました。
error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0 fetch-pack: unexpected disconnect while reading sideband packet fatal: protocol error: bad pack header
つまり、全履歴を一括で取得しようとすると、通常cloneと同じように通信が途中で切断されてしまいました。そこで、一度にすべて取得するのではなく、少しずつ履歴を追加取得する方針に変更しました。
git fetch --deepen=50
「–deepen」は、現在取得済みの履歴に対して、指定したコミット数分だけさらに履歴を深くするオプションです。例えば、「git clone –depth=50」で取得した後に「git fetch –deepen=50」を実行すると、現在の履歴に追加で50コミット分の履歴を取得しにいきます。
ここで注意したいのは、「–depth」と「–deepen」の意味が異なることです。
- 「–depth=50」:最新から50コミット分の履歴を取得する
- 「–deepen=50」:現在の履歴から追加で50コミット分取得する
段階的に履歴を増やしたい場合は、「–depth」よりも「–deepen」を使用する必要があります。実際に「git fetch –deepen=50」を実行したところ、以下のように追加取得に成功しました。
remote: Enumerating objects: 902, done. remote: Counting objects: 100% (902/902), done. remote: Compressing objects: 100% (523/523), done. Receiving objects: 100% (902/902), 176.75 MiB, done. Resolving deltas: 100% (541/541), completed with 162 local objects.
必ず同じ単位で成功するわけではない
「git fetch –deepen=50」が成功したため、次は取得単位を増やして試しました。しかし、「–deepen=100」や「–deepen=70」では、再び通信断のエラーが発生しました。また、一度は成功した「–deepen=50」でも、取得対象によっては失敗することがありました。
その場合は、「–deepen=30」のように小さい値で試してみてください。
全履歴を取得できたか確認する
再度「git fetch –unshallow」を実行したところ、今度は成功しました。段階的に履歴を取得したことで、一度に取得する残りの量が減り、最終的に全履歴を取得できたと考えられます。
全履歴を取得できたかどうかは、以下のコマンドで確認できます。
git rev-parse --is-shallow-repository
このコマンドは、現在のリポジトリがshallow repositoryかどうかを確認するものです。結果が「true」の場合は、まだ全履歴を取得できていません。「false」の場合は、全履歴を取得できています。
git rev-parse --is-shallow-repository false
この結果から、最終的に完全なリポジトリとして取得できたことが確認できました。
まとめ
今回は、大容量のGitリポジトリをcloneする際に発生した通信断エラーと、その対応についてまとめました。
今後、同じように大容量のリポジトリを取得する場面があれば、最初から全量を取得しようとせず、対処方法の一つとして、shallow cloneで取得してから段階的に履歴を取得する方法も検討してみてください。
《関連記事》


