Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8835

GitHub Hacking ~GitHubを容量無制限のクラウドストレージとして使用する試み~

$
0
0

警告

今回紹介している内容はGitHubの公式からは「やるなよ!!」と言われている内容を紹介しています
私のディスク容量はいくつですか?
これを理解した上で以降を読み進めてください

問い

GitHubを容量無制限のクラウドストレージとして使用できるのか?

GitHubには git pushした場合には容量制限があり、1ファイル100MBを超える場合は Git LFSを使って git pushを行わないとエラーが発生してしまいgit pushすることができません。
この仕様については共通の認識としてよく出てきますがリポジトリの総計の容量の上限については言及されていません。そのため、実際にやってみてどこまでできるのか試してみたいと思います。

実際にやってみた結果

console.jpg
finder.jpg

約1254652ファイル約164.6GBのリポジトリ全てGitHubにpushすることに成功しました!!
GitHubすごい!!

finder.jpg
リポジトリはこのような感じになっておりました。
(あまり広めたくないので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ファイル100MB以上のファイルをpushする場合は Git LFSを用いて git pushする(ただし、Git LFSは容量次第で有料になる)
  • 1回の git push2GBを超えるを超える場合エラーになってpushできない(非公式な仕様)

結論

  • 1ファイル100MB以下
  • 1回のpush(1回のcommit)が 2GB以下

上記の条件を満たしていればGitHubの物理的なサーバーストレージの範囲内で無制限のサーバーストレージとして利用できることがわかりました

めんどくさかったのでスクリプトを作った

上記の検証を行なっている時に最初は1回ずつ手作業で git commitgit pushを行なって行きましたが、途方のない作業でしたのでスクリプトを作成して、それを実行するようにしました。
今回はNode.jsで簡単に実行できるスクリプトを作成して実行するようにしました。
.gitignoreの設定は以下のようになります。

*.DS_Store
*~
Thumbs.db
node_modules/

スクリプトの中身は以下のようになります。

// roop-commit-and-push.jsconstfs=require('fs');const{promisify}=require('util')constsimpleGit=require('simple-git');constgit=simpleGit();asyncfunctionexecuteGitStatus(){returngit.status();}constlimitFileSize=1900000000;consteachSlice=(arr,n=2)=>{constdup=[...arr]constresult=[];letlength=dup.length;while(0<length){result.push(dup.splice(0,n));length=dup.length}returnresult;};asyncfunctionexecuteCommitAndPushRoutine(){letstatusResult=awaitexecuteGitStatus();letremainFileCount=statusResult.created.length+statusResult.not_added.length;while(remainFileCount>0){letsumSize=0;// ダブっているファイルがあるためSetにして除去するconstaddFileSet=newSet();constcreatedFilePromises=[];// すでに git add されているファイルの容量を計算して、残りまだgit addできるもののみを全てgit addするfor(constnotAddFileofstatusResult.created){conststatPromise=promisify(fs.stat)(notAddFile).then(stat=>{sumSize=sumSize+stat.size;});createdFilePromises.push(statPromise);}awaitPromise.all(createdFilePromises);console.log(sumSize);if(sumSize<=limitFileSize){// 速度優先のため非同期でgit addするファイルの選別をファイルサイズを取得した上で行うconstaddFilePromises=[];for(constnotAddFileofstatusResult.not_added){letisStop=false;conststatPromise=promisify(fs.stat)(notAddFile).then(stat=>{if(isStop){returnsumSize;}if(sumSize+stat.size>limitFileSize){isStop=true;returnsumSize;}sumSize=sumSize+stat.size;addFileSet.add(notAddFile.toString());returnsumSize;});addFilePromises.push(statPromise);if(isStop){break;}}awaitPromise.all(addFilePromises);}console.log(sumSize);consttotal=addFileSet.size;remainFileCount=remainFileCount-total;console.log("add files:"+total.toString());// git addできるファイル数の上限が約2000。これ以上のファイル数をgit addするとエラーになるので分割するfor(constfilesofeachSlice(Array.from(addFileSet),2000)){awaitgit.add(files).catch(err=>{console.error(err);});}console.log("add file completed:"+total.toString());constnowDate=newDate();constdateString=[nowDate.getFullYear(),nowDate.getMonth(),nowDate.getDay()].join("/");consttimeString=[nowDate.getHours(),nowDate.getMinutes(),nowDate.getSeconds()].join(":");constcommitMessage=[dateString,timeString,total,"image files add"].join("");console.log(commitMessage);awaitgit.commit(commitMessage);console.log("committed "+total.toString()+" files");awaitgit.push().catch(err=>{console.error(err);});console.log("pushed and remained "+remainFileCount.toString()+" files");// git statusで取得できるファイル数には上限があるので、現状で取得できたファイルが無くなったら再度git statusを行なって補充できるか確認するif(remainFileCount<=0){statusResult=awaitexecuteGitStatus();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する必要があるファイルがなくなるまでGitHubgit pushを行なってくれます。
(もちろん事前に git initgit remote add origin urlなどの基本的な初期設定を事前に行なっている必要があります。)

パッケージ化した方が良さそう?

Node.jsのインストールなどの初期設定が面倒な場合は上記スクリプトをパッケージ化して実行してもいいかもしれません。
以下参考
nodeアプリケーションを実行可能ファイルにして出力する

闇の魔術に対する防衛術?

ここまで読んでいただいたらお分かりかと思いますが、防衛者側は GitHubになります。私もGithub Supportからゴルァされたら大人しくGitlabに移行するなど別の方法を模索するようにします...

絶対にやってはダメですよ!!!

今回「もしかしてできるのではないか?」と思い至ったので実際に検証してみました。
しかし公式からは
私のディスク容量はいくつですか?
にあるようにやらないでくださいと明確に指摘されています。

これをみた皆さんは絶対にマネしてはダメですよ!!!
もし同じことを真似しようと思った方はくれぐれも自己責任でやるようにしてください。

なお
2020/12/06 現在、規約違反ではないのでペナルティはないと思われます。


Viewing all articles
Browse latest Browse all 8835

Trending Articles