動機
github のリポジトリのサイズを知るには github API の get を使う。以下のコマンドのsizeを見ればいい。
$ wget -O - 'https://api.github.com/repos/:owner/:repo'
sizeはキロバイト単位。以下のリポジトリの場合、およそ2GBも使っているというわけだ。githubのリポジトリのサイズ上限は1GBなので、この状態はあんまり良くない。
$ wget -q -O - 'https://api.github.com/repos/:owner/:repo' | grep size "size": 1994975,
このリポジトリにgh-pagesブランチが含まれることを確認するために、github API の get branch を使う。
$ wget -q -O - 'https://api.github.com/repos/:owner/:repo/branches' | grep 'gh-pages' "name": "gh-pages",
Github API ではリポジトリ内のブランチごとのサイズを知ることはできないけれど、以下のように git bundle を使えばリポジトリごとのサイズを知ることが可能。ここではリモートリポジトリにgithubと名前がつけられていると仮定している。結果、できたファイルのサイズはおよそ1.63 GiB。このgh-pagesブランチはorphanブランチなので、リモートリポジトリのサイズが大きいのはこのgh-pagesブランチが元凶と考えて差し支え無いだろう。ということでgh-pagesブランチを小さくする。
$ git bundle create ../remote.github.gh-pages remotes/github/gh-pages Counting objects: 282396, done. Delta compression using up to 2 threads. Compressing objects: 100% (3644/3644), done. Writing objects: 100% (282396/282396), 1.63 GiB | 10.52 MiB/s, done. Total 282396 (delta 276770), reused 282395 (delta 276770)
最新の状態を表すコミットだけにする例
remotes/github/gh-pages の最新状態と同じ状態を持つ orphan ブランチ (gh-pages/latest) を作り、その状態をコミットして、ブランチの状態に差がないことを確認する。
$ git checkout --orphan gh-pages/latest remotes/github/gh-pages Switched to a new branch 'gh-pages/latest' $ git commit --no-verify --message 'squash commits' [gh-pages/latest (root-commit) 513b848] squash commits 6232 files changed, 2824065 insertions(+) $ git diff remotes/github/gh-pages gh-pages/latest
この例では、古いコミットログがすべて失われる。問題があれば、git log でコミットログの内容を保存しておいて、git commit 時に --file オプションで追加する。
最初のコミットから XX 個のコミットをまとめて、以降は同様のコミットを繰り返す例。
N 個おきに squash コミットを作成する例
remotes/github/gh-pages | gh-pages/squash/all/1 | gh-pages/squash/XX/1 | gh-pages/squash/XX/YY | ||||
---|---|---|---|---|---|---|---|
hash | message | hash | message | hash | message | hash | message |
root | initial commit | root | squash all commits | root | squash XX commits | root | squash XX commits |
... | ... | ||||||
XX-1 | update | ||||||
XX | update | (XX)-(XX-1)=1 | update | ... | ... | ||
... | ... | ... | ... | ||||
(YY-1)*XX-1 | update | ((YY-1)*XX-1)-(XX-1)=(YY-2)*(XX-1) | update | ||||
(YY-1)*XX | update | ((YY-1)*XX)-(XX-1)=XX+1 | update | YY-1 | squash XX commits | ||
... | ... | ... | ... | ||||
YY*XX-1 | update | (YY*XX-1)-(XX-1) | update | ||||
YY*XX | update | (YY*XX)-(XX-1) | update | (YY*XX)-(XX-1) | update | ||
... | ... | ... | ... | ... | ... | ||
N-1 | update | (N-1)-(XX-1) | update | (N-1)-(XX-1) | update |
適当なコミットと同じ状態を持つコミットのみから構成されるブランチ (gh-pages/duplicate) を作る例
最初に orphan ブランチを作成する。以降の作業はこのブランチで行う。
$ git checkout --orphan gh-pages/duplicate Switched to a new branch 'gh-pages/duplicate'
orphan ブランチなのでなにもないはずだが、tracking ファイルと untracking ファイルを削除してワーキングコピーを整理しておく。
$ git rm --ignore-unmatch -r -- . $ git clean --force -d -x
既存のコミット aaaaaaa の内容をワーキングコピーに反映させる。これには以下のコマンドを使う。ここでは aaaaaaa が empty コミットなのでエラーが出ているが、これは期待通りの結果。
$ git checkout aaaaaaa -- . error: pathspec '.' did not match any file(s) known to git.
ワーキングコピーの内容をコミットする。この時、 --reuse-message を使ってコミットメッセージと著者の情報は aaaaaaa の情報から複製する。ここでは新たに AAAAAAA が作成された事がわかる。
$ git commit --no-verify --allow-empty --allow-empty-message --reuse-message=aaaaaaa [gh-pages/duplicate (root-commit) AAAAAAA] (snip)
AAAAAAA と aaaaaaa の tree や blob オブジェクトは同じはずなので、git diff でこれを確かめる。何もメッセージが戻ってこなければ正解。また、両者のログを表示すると、コミッタの名前とメールアドレスとコミット時間には違いがあることがわかる。この情報も複製したければ、GIT_COMMITTER_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL などの環境変数を aaaaaaa のそれと同じものに設定して git commit を実行する。
$ git diff --name-status aaaaaaa AAAAAAA $ git log --show-signature --pretty=fuller -1 aaaaaaa commit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Author: author <author@example.com> AuthorDate: Thu Jan 1 00:00:00 1970 +0000 Commit: comitter <comitter@example.com> CommitDate: Thu Jan 1 00:00:00 1970 +0000 $ git log --show-signature --pretty=fuller -1 AAAAAAA commit AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Author: author <author@example.com> AuthorDate: Thu Jan 1 00:00:00 1970 +0000 Commit: dummy comitter <dummy-comitter@example.org> CommitDate: Mon Jan 18 15:14:08 2038 +1200
次に既存のコミット eeeeeee を元に新しいコミットを作る事を考える。同じことをやれば良いのだが、その前に、eeeeeee のひとつ前のコミット (すなわち eeeeeee^1) を元にコミットを作っておくことについて考えることには価値がある。なぜなら、eeeeeee^1 と eeeeeee の変化を記録するにはこれが必要だからである。ここではその方針をとる。
eeeeeeee^1 を元に新しいコミット DDDDDDD を作って内容を確認する手順は先のものと同じ。ここで注目すべきは git rm でファイルが削除されているということ。これを行わないと、その後に git commit する際に不適切なマージ (eeeeeeee^1 の状態を保存しないマージ) が行われる。
$ git rm --ignore-unmatch -r -- . (snip) $ git clean --force -d -x $ git checkout eeeeeeee^1 -- . $ git commit --no-verify --allow-empty --allow-empty-message --reuse-message=eeeeeee^1 [gh-pages/duplicate DDDDDDD] update contents (snip) $ git diff --name-status eeeeeee^1 DDDDDDD $ git log --show-signature --pretty=fuller -1 eeeeeee^1 commit dddddddddddddddddddddddddddddddddddddddd Author: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> AuthorDate: Sun Jul 26 09:00:00 2015 +0900 Commit: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> CommitDate: Sun Jul 26 09:00:00 2015 +0900 update contents $ git log --show-signature --pretty=fuller -1 DDDDDDD commit DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD Author: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> AuthorDate: Sun Jul 26 09:00:00 2015 +0900 Commit: dummy comitter <dummy-comitter@example.org> CommitDate: Mon Jan 18 15:14:08 2038 +1200 update contents
同様に、eeeeeeee を元に新しいコミット EEEEEEE を作って内容を確認する
$ git rm --ignore-unmatch -r -- . (snip) $ git clean --force -d -x $ git checkout eeeeeee -- . $ git commit --no-verify --allow-empty --allow-empty-message --reuse-message=eeeeeee [gh-pages/duplicate EEEEEEE] update contents $ git diff --name-status eeeeeee EEEEEEE $ git log --show-signature --pretty=fuller -1 eeeeeee commit eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee Author: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> AuthorDate: Wed Jul 29 09:00:00 2015 +0900 Commit: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> CommitDate: Wed Jul 29 09:00:00 2015 +0900 update contents (d-u@jp:57772) $ git log --show-signature --pretty=fuller -1 EEEEEEE commit EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE Author: AYANOKOUZI, Ryuunosuke <i38w7i3@yahoo.co.jp> AuthorDate: Wed Jul 29 09:00:00 2015 +0900 Commit: dummy comitter <dummy-comitter@example.org> CommitDate: Mon Jan 18 15:14:08 2038 +1200 update contents (d-u@jp:57772)
他にも保存したいコミットがあれば、そのひとつ前のコミットとそのコミットを eeeeeee^1 と eeeeee でやったのと同じ手順で保存していけばよい。
現状を図に表すと以下の様な感じになった。ここでは直線的なコミット履歴を持つブランチを元に作業を行ったが、上記の方法はもっと複雑なコミット履歴を持つブランチに対しても同様に適用できる。
gh-pages/source: aaaaaaa -> bbbbbbb -> ccccccc -> ddddddd -> eeeeeee -> fffffff -> ggggggg gh-pages/duplicate: AAAAAAA -----------------------> DDDDDDD -> EEEEEEE