できない.dev

Git で大きなファイル(100MB 超)が push できない

GitHub は単一ファイル 100MB を上限としており、超えた blob は push が拒否される。
履歴に紛れたまま push が通らなくなるので、Git LFS に乗せるか filter-repo で履歴から削除する。

公開: 更新:

症状できない
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize) %(rest)' | awk '$1 == "blob" && $2 >= 104857600'
blob 110100480 big.bin

2026-10-13 に alpine:3 で実際に打って取った出力。検証環境の詳細

要約

remote: error: File ... is 123.45 MB; this exceeds GitHub's file size limit of 100.00 MB は、GitHub の 単一ファイル 100MB 上限 に当たった状態。
最新コミットから消すだけでは履歴に blob が残っているため push できない。
Git LFS への移行か、git filter-repo での履歴掃除のどちらかが必要。

実行例

105 MiB の blob を含む履歴では、git rm で消してコミットしても 100 MiB 以上の blob が履歴に残り、.git も 105.2M のままだった。git filter-repo --path big.bin --invert-paths で履歴から取り除くと該当する blob が見つからなくなり、.git は 188.0K まで縮んでいる。git lfs track した design.psd は、実体の 1048576 バイトではなく 132 バイトのポインタファイルがコミットされていた。

$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize) %(rest)' | awk '$1 == "blob" && $2 >= 104857600'
blob 110100480 big.bin
$ du -sh .git
105.2M	.git
$ git rm -q big.bin
$ git commit -qm "remove big.bin"
$ git ls-files
README.md
$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize) %(rest)' | awk '$1 == "blob" && $2 >= 104857600'
blob 110100480 big.bin
$ du -sh .git
105.2M	.git
$ git filter-repo --path big.bin --invert-paths --force
Parsed 3 commits
HEAD is now at b5e50c2 init
 
New history written in 0.01 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
Completely finished after 0.04 seconds.
$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize) %(rest)' | awk '$1 == "blob" && $2 >= 104857600'
$ du -sh .git
188.0K	.git
$ git log --oneline
b5e50c2 init
$ git lfs track "*.psd"
Tracking "*.psd"
$ git add .gitattributes design.psd
$ git commit -qm "track psd via LFS"
$ git lfs ls-files
a81ff5a778 * design.psd
$ git cat-file -s HEAD:design.psd
132
$ git cat-file -p HEAD:design.psd
version https://git-lfs.github.com/spec/v1
oid sha256:a81ff5a7784a83a8609b2c80dbd7eca163d28ed648207b421abfee46ffd92759
size 1048576

— 2026-10-13 時点の出力

検証環境2026-10-13 検証
検証日
実行環境
alpine:3 Alpine Linux v3.24

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

1. Git LFS に乗せる

git lfs install
git lfs track "*.psd"
git add .gitattributes
git add path/to/big.psd
git commit -m "track psd via LFS"
git push

LFS は実体を専用ストレージに置き、Git には参照ポインタだけ入れる仕組み(Git LFS 公式(新しいタブで開く))。
新規ファイル用には最も素直な解。

2. 履歴から完全削除

pip install git-filter-repo
git filter-repo --path big.bin --invert-paths
git push --force-with-lease

GitHub の Managing large files ドキュメント(新しいタブで開く) のとおり、過去コミットの blob は履歴を書き換えないと消えない。
force push は共同作業者と必ず調整する。

3. 別ストレージに移す

ビルド成果物 → GitHub Releases / Actions の Artifacts
データセット → S3 / Cloud Storage / Hugging Face
バイナリ依存 → パッケージレジストリ

長期保管はリポジトリ外に逃がし、リポジトリには取得スクリプトだけ残す。
clone 速度も改善する。

4. 再発防止

node_modules/
dist/
*.zip
*.mp4
*.psd

.gitignore で先に弾いておく。
commit 前に git diff --cached --stat でサイズを目視確認する習慣も有効。

よくある原因

  1. 100MB 超を commit してしまった: 動画 / アーカイブ / モデルファイルを誤ってリポジトリに入れた。
  2. 履歴に残っている: 直近で git rm しても、過去コミットに blob が残っているため push 拒否は解消しない。
  3. LFS 未導入: 大ファイルを通常 blob として扱っているため、clone も push も重い。
  4. build 成果物の混入: dist や *.tar.gz が .gitignore に追加される前に commit されている。

この手順で直った?