警告
今回紹介している内容はGitHubの公式からは「やるなよ!!」と言われている内容を紹介しています
私のディスク容量はいくつですか?
これを理解した上で以降を読み進めてください
問い
GitHubを容量無制限のクラウドストレージとして使用できるのか?
GitHub には git push
した場合には容量制限があり、1ファイル100MB
を超える場合は Git LFS を使って git push
を行わないとエラーが発生してしまいgit push
することができません。
この仕様については共通の認識としてよく出てきますがリポジトリの総計の容量の上限については言及されていません。そのため、実際にやってみてどこまでできるのか試してみたいと思います。
実際にやってみた結果
約1254652ファイル
、約164.6GB
のリポジトリ全てGitHubにpushすることに成功しました!!
GitHubすごい!!
リポジトリはこのような感じになっておりました。
(あまり広めたくないのでprivateにしています)
ダウンロードできるの?
上記のリポジトリをGitHub上のzipにしてダウンロードすることは怖かったのでやっていません。
git clone
を用いたダウンロードはできたので、ダウンロードするときは git clone
を用いてダウンロードしてください
きっかけ
去年(2019年)のアドベントカレンダーにてプチ炎上しましたこちらの記事
-
ハッカソンの開催情報を自動でお知らせするBotをGithub Actionsに移行して運用費が0円になりました
この内容を実践していた時に
1ファイル100MB以下にする仕様を満たしていれば、容量の際限[GitHub](https://github.com/)にアップロードできるのではないか?
という疑問を抱いたため実験も兼ねて実践してみようと思いました。
(ちなみにプチ炎上した記事のその後の展開は後日記事にします。現在、この記事に書かれていることはGitHubでは行なっておらず、Gitlabにて行なっております)
そしてこちらの記事
記事を作成し、運営していた時に収集した画像ファイルが AWS S3
に保管していて管理費用がかかっていたので、費用削減も兼ねてできたらいいなという希望も込めて検証しました。
実践してみて判明したGitHubの仕様
-
1ファイル100MB
以下にする → 1ファイル100MB以上のファイルをpushしたときはエラーになってpushができないため - 1回の
git push
で2GB
を超えるを超える場合エラーになってpushできない(非公式な仕様)
結論
- 1ファイル100MB以下
- 1回のpush(1回のcommit)が
2GB
以下
上記の条件を満たしていればGitHubの物理的なサーバーストレージの範囲内で無制限のサーバーストレージとして利用できることがわかりました
めんどくさかったのでスクリプトを作った
上記の検証を行なっている時に最初は1回ずつ手作業で git commit
と git push
を行なって行きましたが、途方のない作業でしたのでスクリプトを作成して、それを実行するようにしました。
今回はNode.jsで簡単に実行できるスクリプトを作成して実行するようにしました。
.gitignore
の設定は以下のようになります。
*.DS_Store
*~
Thumbs.db
node_modules/
スクリプトの中身は以下のようになります。
// roop-commit-and-push.js
const fs = require('fs');
const { promisify } = require( 'util' )
const simpleGit = require('simple-git');
const git = simpleGit();
async function executeGitStatus(){
return git.status();
}
const limitFileSize = 1900000000;
const eachSlice = (arr, n = 2) => {
const dup = [...arr]
const result = [];
let length = dup.length;
while (0 < length) {
result.push(dup.splice(0, n));
length = dup.length
}
return result;
};
async function executeCommitAndPushRoutine(){
let statusResult = await executeGitStatus();
let remainFileCount = statusResult.created.length + statusResult.not_added.length;
while(remainFileCount > 0){
let sumSize = 0;
// ダブっているファイルがあるためSetにして除去する
const addFileSet = new Set();
const createdFilePromises = [];
// すでに git add されているファイルの容量を計算して、残りまだgit addできるもののみを全てgit addする
for(const notAddFile of statusResult.created){
const statPromise = promisify(fs.stat)(notAddFile).then(stat => {
sumSize = sumSize + stat.size;
});
createdFilePromises.push(statPromise);
}
await Promise.all(createdFilePromises);
console.log(sumSize);
if(sumSize <= limitFileSize) {
// 速度優先のため非同期でgit addするファイルの選別をファイルサイズを取得した上で行う
const addFilePromises = [];
for (const notAddFile of statusResult.not_added) {
let isStop = false;
const statPromise = promisify(fs.stat)(notAddFile).then(stat => {
if(isStop){
return sumSize;
}
if (sumSize + stat.size > limitFileSize) {
isStop = true;
return sumSize;
}
sumSize = sumSize + stat.size;
addFileSet.add(notAddFile.toString());
return sumSize;
});
addFilePromises.push(statPromise);
if (isStop) {
break;
}
}
await Promise.all(addFilePromises);
}
console.log(sumSize);
const total = addFileSet.size;
remainFileCount = remainFileCount - total;
console.log("add files:" + total.toString());
// git addできるファイル数の上限が約2000。これ以上のファイル数をgit addするとエラーになるので分割する
for(const files of eachSlice(Array.from(addFileSet), 2000)){
await git.add(files).catch(err => {
console.error(err);
});
}
console.log("add file completed:" + total.toString());
const nowDate = new Date();
const dateString = [nowDate.getFullYear(), nowDate.getMonth(), nowDate.getDay()].join("/");
const timeString = [nowDate.getHours(), nowDate.getMinutes(), nowDate.getSeconds()].join(":");
const commitMessage = [dateString, timeString, total, "image files add"].join(" ");
console.log(commitMessage);
await git.commit(commitMessage);
console.log("committed " + total.toString() + " files");
await git.push().catch(err => {
console.error(err);
});
console.log("pushed and remained " + remainFileCount.toString() + " files");
// git statusで取得できるファイル数には上限があるので、現状で取得できたファイルが無くなったら再度git statusを行なって補充できるか確認する
if(remainFileCount <= 0) {
statusResult = await executeGitStatus();
remainFileCount = statusResult.created.length + statusResult.not_added.length;
}
}
}
executeCommitAndPushRoutine();
上記スクリプトを実行するためにまずは simple-git をインストールします。
(package.json
を作るほどのものでもないと思うのでこちらは省略)
npm install simple-git
そして、その後
node roop-commit-and-push.js
として上記のスクリプトを実行すると、git add
する必要があるファイルがなくなるまでGitHubにgit push
を行なってくれます。
(もちろん事前に git init
git remote add origin url
などの基本的な初期設定を事前に行なっている必要があります。)
パッケージ化した方が良さそう?
Node.jsのインストールなどの初期設定が面倒な場合は上記スクリプトをパッケージ化して実行してもいいかもしれません。
以下参考
nodeアプリケーションを実行可能ファイルにして出力する
闇の魔術に対する防衛術?
ここまで読んでいただいたらお分かりかと思いますが、防衛者側は GitHub になります。私もGithub Support
からゴルァされたら大人しくGitlabに移行するなど別の方法を模索するようにします...
絶対にやってはダメですよ!!!
今回「もしかしてできるのではないか?」と思い至ったので実際に検証してみました。
しかし公式からは
私のディスク容量はいくつですか?
にあるようにやらないでくださいと明確に指摘されています。
これをみた皆さんは絶対にマネしてはダメですよ!!!
もし同じことを真似しようと思った方はくれぐれも自己責任でやるようにしてください。
なお
2020/12/06 現在、規約違反ではないのでペナルティはないと思われます。