20201206のGitに関する記事は7件です。

1人で始まり、1人で終わるPull request入門

1人ではじまり1人で終わるPull Request

今回は一人でできるGitHubのPull Requestの練習について紹介します。

*当記事は実践的なチーム開発を想定した記事でありません。私が個人でPull Requestの練習をした内容をまとめたものです。

Pull Requestについて

Pull RequestとはGitHubの機能の一つでソースレビューや作成もしくは変更したソースコードの反映を行うために利用される機能です。


最近ではチーム開発にGit GitHubの導入をしている企業は多くなっています。

Gitのバージョン管理はとても優れていますが、開発に携わる人間が各々ソードコードの新規作成や変更などを自己判断で反映を行った場合、チームメンバーはひとつひとつ変更内容の確認を行う必要があり、チーム開発においてとても非効率的な作業が発生します。また、チームのリーダーや有識者によるコードレビューがない場合は変更した内容により障害の発生原因となる場合があります。

なのでPull Requestが存在します!

Pull Requestの流れは

プルリク

上記のような流れで反映を行う前に人間を挟むことにより反映前にコードレビューが必ず発生するようになります。

雑な資料で申し訳ありません。

Pull Requestを実践する

はじめに

  • Gitのインストール

  • GitHubアカウント

上記項目が未完了の場合、先に完了させましょう。

Git

GitHub

リポジトリの作成を行う

リポジトリ

まずはじめにリポジトリの作成を行います!

リポジトリはPublicPrivateお好きな方をお選びください。


作成

次にローカルのリポジトリとリモートのリポジトリの紐付けを行います。

私はGitHubとSSHで接続をしているので、SSHを選択していますがお使いの環境にあわせて接続形式を選択してください。


画面

リモートリポジトリにローカルの内容をpushを行い、GitHubのリポジトリの画面が更新されていれば準備完了です。

これで1人でPull Requestの練習を行う準備が完了しました!


Pull Requestを出してみる

まずローカルリポジトリに新規ブランチを作成しましょう。

git checkout -b develop

develop branchの作成ができました。次にソースコードを編集または新規作成を行い、コミットを行いましょう。

コミットが完了したらリモートリポジトリにpushしましょう。

git push origin HEAD

gamen

  1. develop branchがpushされていることを確認します。Compare & pull requestボタンがからPull requestの画面に移動できます。今回はこのボタンからの遷移はおこないません。

  2. 今回はPull requestを行うため pull requestsタブからpull requestを行います。


画面2

New pull requestボタンを押してpull requestを行います。


画面3

  1. Merge先のbranchとMergeするbranchを指定します。今回はdevelop branchmain branchにMergeします。

  2. commitのメッセージ内容を確認することができます。今回はcommitが1つなので1つしか表示されていませんが、commitの内容が複数ある場合は複数表示されます。

  3. 変更したファイルの内容を確認することができます。今回は新規のファイルを作成したので追加した内容のみ表示されています。一部削除をした場合は削除した内容が表示されます。

  4. Create pull requestボタンを押すことで確認ページに移動することができます。


gamen3

  1. Pull requestのタイトルを記述する項目です。初期時はコミットの内容が表示されます。この項目はわかりやすい内容にしましょう。

  2. Pull requestのコメント内容を記述する項目です。①でタイトルの記述を行い、当項目でより詳しい内容を記述します。記述内容としてはどのような変更をしたのかもしくはレビューをして欲しい観点についてを記述をします。

  3. pull requestの内容を分別する。

  • Reviewers レビューをしてもらう人を選択する。

  • Assignees 担当した人間を選択する。

  • Labels どうのような作業かを分類かを選択する。

  • Proects どのプロジェクトにたいしてのpull requestかを選択する。

  • Miletone いつまでの期限の作業かを選択する。

  • Linked Issue Issueごとに作業を管理している場合、どの作業かを選択する。

*今回は1人で始まり、1人で終わるpull requestなのでReviewersは選択することはできません。

上記の内容が完了したらCreate pull requestボタンを押しましょう!


4

ついに最後の画面です。

本来であればレビュー担当者がコメントを記述することができますが、今回は1人での作業のため、自身のコードレビューを行いコメントをしましょう。

Merge pull reqestボタンを押すことでdevelop branchmain branchにMergeすることができます。ボタンを押すとpull reqeustのコメントを記述することができます。コメントの記述が完了したらConfirm Mergeボタンを押しましょう。


5

最後にdevelop branchを削除してGitHubでの作業は完了です!


リモートをローカルに反映する

リモートリポジトリとローカルリポジトリで差があるので、リモートリポジトリの内容をローカルリポジトリに反映しましょう。今回の場合、リモートリポジトリのmain branchdevelop branchをMergeした状態です。一方でローカルリポジトリのmain branchdevelop branchをMergeしていません。

なので、リモートリポジトリのmain branchをローカルのmain branchにpullしましょう。

git checkout main

まずmain branchに移動します。

git pull origin main

次にリモートのmain branchをローカルのmain branchにpullします。

git log

最後にMergeが正常に行えているかを確認します。

以上が1人で始まり、1人で終わるPull request入門です。

pull requestの練習がしてみたいが、やり方がわからないという人や擬似チーム開発を1人で練習してみたいひとは参考にしてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心に帰れた!】" fatal: Not a git repository (or any of the parent directories): .git " の対処法

初めに(状況)

・今回扱う自分のGit学習歴:3か月目
・Gitを使ってGithub内でデータを管理する操作に少し小慣れてきた時期。
 そんな時に今回のエラーが発生しました。

ターゲット

自分と同じ少しGitの扱いに小慣れてきた方

事象

・Vue.jsの勉強ようにGitHubを使ってリモートリポジトリで管理しようとした
・いつも通り以下コマンドを実行しようとコマンド入力

git add .
git commit -m "first commit"

・しかし以下エラーが出てできない。。。

fatal: Not a git repository (or any of the parent directories): .git

・なぜだ???

結論

原因は以下いずれかの処理ができていないため
1. Github内の設定が間違っている
2. git のセットアップができていない
3."git init(ファイルの初期化)"をしていなかった ← 自分のエラーの原因・・・

解決方法詳細

1.Github内の設定が間違っている

<解決策>
・Github内で"my page" ⇒ "Settings" ⇒ "Emails" に移動
・以下選択肢から:ballot_box_with_check:を外す
Email settings - Google Chrome 2020_12_06 18_40_10 (2).png

2.git のセットアップができていない

<解決策>
以下Gitのセットアップを実施する

$ git config --global user.name "xxxx"
$ git config --global user.email "xxxxxx@gmail.com"

3."git init(ファイルの初期化)"をしていなかった ← 今回の自分のエラーの原因・・・

<解決策>
一番シンプル。以下コマンドを実行するだけ。

git init // 新しいリポジトリ作成 //

その後は以下コマンドも問題なく実行しました。

git add .
git commit -m "first commit"

最後に

非常に情けないミスででしたが、こんな初歩初歩のところでつまづくこともあるんだな、と初心に帰ることができたいい機会でした!
皆さんもこんなシンプルな凡ミスをしたら
・凡ミスしても笑って凡ミスした自分を受け入れる!
・気落ちせず「初心に帰れた!ラッキー!」くらいで次の作業を進めましょう!

最後まで読んでいただきありがとうございました!

※参考

  1. エラー:fatal: Not a git repository (or any of the parent directories): .git 対処方法
  2. GitHub でエラーが出た時(Not a git repository)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

チーム開発で必要なgitコマンド【学習用まとめ】

チーム開発をするにあたって、最低限必要なコマンドを学習用にまとめました。

前提となるGitの仕組みと各コマンドの意味を理解して、それらを適切に使ったら、コンフリクトは発生しなくなった。

Gitが管理するファイルの3つの段階

ローカルにおいて、Gitはファイルのバージョンを管理するにあたって、ファイルを3つの段階に分けて扱っている。

①作業エリア

・開発者がファイルの変更を行った段階
・まだGitは変更を管理してない

②ステージングエリア

・変更が登録される準備段階
・git addされた段階

③ローカルリポジトリ

・変更がリポジトリに登録された段階
・git commitされた段階

gitコマンド

git status

・Gitの状態を確認する

git add ファイル名

・指定したファイルをリポジトリに追加する
・指定されたファイルはステージングエリアに格納される

git commit

・addで追加されたファイルをリポジトリに保存する
・コミットの段階でファイルの記録が保存される

git branch ブランチ

・ブランチを作成する
・引数がない場合はブランチ一覧と現在のブランチが表示される

git checkout ブランチ

・ブランチを移動する

git clone コピー元のリポジトリ (コピー先ディレクトリ)

・リポジトリの複製
・予めクローン先のディレクトリを作成し、そのディレクトリに移動してコマンド入力するか、コピー先のディレクトリを指定する

git pull origin リモートブランチ

・ローカルブランチにリモートブランチの内容を取り込み、ローカルブランチをリモートブランチに同期させる
・同期させたいローカルブランチで行う

git push origin リモートブランチ

・リモートブランチにローカルブランチの変更を送る
・変更を反映させたいローカルブランチで行う

git merge ローカルブランチ

・ローカルブランチ同士を結合させる

ブランチAにブランチBを結合させたい場合

$ git checkout A #ブランチAに移動
$ git merge B #ブランチBをブランチAに結合

まとめ

どのブランチで作業をしているのか?
ファイルの状態はどうなっているか?

をgit branch、git statusコマンドで確認しながら、必要な操作をしていけばコンフリクトはそうそう発生しないはず、、、

参考
https://qiita.com/wann/items/688bc17460a457104d7d

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-Git-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E5%8F%96%E5%BE%97

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

警告

今回紹介している内容は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にアップロードできるのではないか?

という疑問を抱いたため実験も兼ねて実践してみようと思いました。
(ちなみにプチ炎上した記事のその後の展開は後日記事にします。現在、この記事に書かれていることは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.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に移行するなど別の方法を模索するようにします...

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

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

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

警告

今回紹介している内容は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.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 する必要があるファイルがなくなるまでGitHubgit push を行なってくれます。
(もちろん事前に git init git remote add origin url などの基本的な初期設定を事前に行なっている必要があります。)

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

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

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

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

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

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

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

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

警告

今回紹介している内容は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.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 する必要があるファイルがなくなるまでGitHubgit push を行なってくれます。
(もちろん事前に git init git remote add origin url などの基本的な初期設定を事前に行なっている必要があります。)

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

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

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

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

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

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

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

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gitで異なるバージョンの2ファイルの差分を見る方法

コマンド

diff -u <(git cat-file -p HEAD:file1.rb) <(git cat-file -p HEAD^^:file2.rb)

豆知識

GitHubのコメントに貼り付ける時は、(```diff) でスニペットを囲ってやったらいい感じに色がついて見やすくなる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む