huguma’s blog (仮)

IT技術関連中心の備忘録

GitHubの各種サイズ上限とファイル削除の方法

GitHubはかなり大きなファイルやプロジェクトも受け付けますが上限はあります。

GitHub Help - What is my disk quota?

GitHub Help - Working with large files

まとめると次の通りです。

  • リポジトリサイズには物理的な上限は設定していない
    • ただし1GB以下に収めるようにという要請(お願い?)がある
    • それを超えると注意(要請)メールが送られる場合あり
  • その中の単一ファイルには100MBまでという物理的上限がある
    • 50Mを超えるファイルがあると警告を出す
    • 100Mを超えるファイルは受け付けない

GitHubリポジトリサイズの確認方法

この「リポジトリサイズ」はローカルリポジトリのディスク消費量ではなく、たぶんGitHub側が実際に使用しているリソース消費量のことです。

GitHub内部の話なので詳細は分かりませんが、この解釈が一番自然だと思います。

これはGitHub APIを使って取得できます。方法は簡単で、次のURLにアクセスすればリポジトリ情報を取得できます(ブラウザを使うのが一番簡単です)。

  • https://api.github.com/repos/ユーザ名/リポジトリ名

リポジトリ情報はJSON形式で返されます。リソース使用量は"size"プロパティで、単位はkbyteです。

{
  ...
  "size": 3504,
  ...
}

この値が”1048576`(1024 x 1024)を超えたら要対策ということになります。

ただし総サイズが1Gを超えても注意メールが来るのは少し先の事でしょう。私は今まで何回か1Gを超えた事がありますが、割と早く気付いて削減対応したところ何も来ませんでした。

gitからファイルを完全消去するには

gitのリポジトリ履歴からファイルを完全に削除しなければならない状況が時々発生します。GitHubを利用している場合でいくつか例を上げてみます。

  • サイズが1Gを超えた(かなりの猶予期間があるはず、落ち着いて対応すればOK)
  • 単一ファイルが100Mを超えた(これは厳密に拒否されてしまう)
  • パスワードや恥ずかしい写真(?)を間違えて一緒にコミットした(すぐ抹殺せねば...)

無理せず作り直すのが簡単

もしそのリポジトリを自分ひとりで管理しており、作り直してもどこからも文句が来ないのであればそれが一番簡単です。

GitHub側のリポジトリは削除して同じ名前で作り直してもいいですが、それよりpush時に--forceを指定すればリモート側の履歴を無視して強制的に送信・書き換えができます(作り直しの場合は--forceを指定しないとエラーになります)。

$ git push origin --force --all

GitHub側は削除して作り直すとそれまでの履歴は全て消去されますが、この方法では過去にいつ何回commitしたという記録は残り、ユーザページのContributionに表示されます。

リポジトリを残したまま消すのはやや高度

大事なリポジトリなので今までの履歴は残しておきたい(またはそうしないと他人に迷惑がかかる)場合の救済手段は次に書かれています。

GitHub Help - Remove sensitive data

ここの"Purging a file from your repository's history"にgit filter-branchコマンドを使った9ステップの方法があります。

もし間違えてもやり直しの効かない危険作業だということを忘れずに。最低限丸ごとバックアップするかgit cloneしてから作業して下さい。

リポジトリ履歴からファイルを強制的に取り除くにはgit filter-branchを使います。

$ git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch ファイル名' --prune-empty --tag-name-filter cat -- --all

各オプションの意味は次の通りです。

  • --force 強制的に実行
  • --index-filter 'コマンド' コマンドを実行(以下は削除の例)
    • --index-filter 'git rm --cached --ignore-unmatch ファイル' ファイルを全commitから削除
    • --index-filter 'git rm -r --cached --ignore-unmatch ディレクトリ' ディレクトリごと全commitから削除
  • --prune-empty コマンドを実行(削除)した結果空になるcommitを削除
  • --tag-name-filter cat -- --all 該当範囲を全ブランチとtagに設定

メインテナンス用特殊コマンドなのでかなり複雑です。詳しくはリファレンスを参照してください(でも正直言って私はほとんど読んでません...)。

http://git-scm.com/docs/git-filter-branch

結果をよーく確認して、OKならremote側の履歴から消すために強制全pushします。

$ git push origin --force --all

リリースタグを使っている場合はもうひとつ次も必要です。

$ git push origin --force --tags

複数で共同作業している場合はこの後さらにgit rebaseを使った「共有歴史の洗浄」作業が必要になるでしょう(これがドキュメントのstep 8)。しかし私にはこの経験はありませんので文献だけ示しておきます。

http://git-scm.com/book/ja/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9

削除してもすぐには反映されない

実は削除しても実際の更新作業は即時には行われません。gitはそれ自体が高度なファイルシステムで、操作手順は一時的にキャッシュされ後でバックグラウンドジョブが処理しています。

詳しくは次を参照。ただしそんなに深く理解する必要はないと思います。

http://git-scm.com/book/ja/Git%E3%81%AE%E5%86%85%E5%81%B4-%E3%83%91%E3%83%83%E3%82%AF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB

ローカルリポジトリに関しては次のコマンドでバックグラウンドジョブを強制実行して完全消去する手段があります。

$ git gc --prune=now

でもこちらからコマンドを送ってGitHub側にこれを行わせる方法はどうもないようです。しばらくすればGitHubが処理してくれるはずです。

私は実際にこの削除作業を行ったことがありますが、APIが返すsizeは数日間変わりませんでした。こればかりはGitHubを信じて待つしかないようです。