リポジトリサイズの削減
Git リポジトリは時間とともに大きくなります。Git リポジトリに大きなファイルが追加された場合:
- ファイルをダウンロードしなければならないので、リポジトリの取得が遅くなります。
- サーバーのストレージスペースを大量に消費します。
- Git リポジトリのストレージの制限に達する可能性があります。
リポジトリを書き換えることで、不要な履歴を削除してリポジトリを小さくすることができます。** git filter-branch
やBFGよりもgit filter-repo
** をおすすめします。
リポジトリサイズの計算
リポジトリのサイズは、リポジトリ内のすべてのファイルの累積サイズを計算することで求められます。リポジトリのハッシュ化されたストレージパスで du --summarize --bytes
を実行するのと似ています。
リポジトリ履歴からファイルを削除
GitLab はハウスキーピングの一環として、到達不可能なオブジェクトを削除します。GitLab では、リポジトリのディスクサイズを手動で小さくするには、まずブランチやタグ、GitLab が作成したその他の内部参照 (refs) から大きなファイルへの参照を削除する必要があります。これらの参照には次のようなものがあります:
refs/merge-requests/*
refs/pipelines/*
refs/environments/*
refs/keep-around/*
これらの参照は自動的にはダウンロードされず、非表示の参照は宣伝されませんが、プロジェクトのエクスポートを使ってこれらの参照を削除することができます。
GitLab リポジトリからファイルをパージするには:
-
サポートされているパッケージマネージャを使うか、ソースから
git filter-repo
とオプションでgit-sizer
をインストールします。 -
プロジェクトから新しいエクスポートを作成し、ダウンロードします。このプロジェクトエクスポートには、リポジトリのバックアップコピーと、リポジトリからファイルをパージするために使用できる参照が含まれています。
-
tar
を使ってバックアップを解凍します:tar xzf project-backup.tar.gz
これには
git bundle
で作成されたproject.bundle
ファイルがコンテナとして含まれています。 -
--bare
と--mirror
オプションを使って、バンドルからリポジトリの新しいコピーをクローンします:git clone --bare --mirror /path/to/project.bundle
-
project.git
ディレクトリに移動します:cd project.git
-
バンドルファイルからのクローンでは、
origin
リモートがローカルのバンドルファイルに設定されるため、リポジトリの URL に変更してください:git remote set-url origin https://gitlab.example.com/<namespace>/<project_name>.git
-
git filter-repo
またはgit-sizer
のいずれかを使用して、リポジトリを分析し、結果をレビューして、パージするアイテムを決定します:# Using git filter-repo git filter-repo --analyze head filter-repo/analysis/*-{all,deleted}-sizes.txt # Using git-sizer git-sizer
-
関連する
git filter-repo
オプションを使用して、リポジトリの履歴をパージします。一般的なオプションは以下の2つです:-
--path
と--invert-paths
で特定のファイルをパージできます:git filter-repo --path path/to/file.ext --invert-paths
-
--strip-blobs-bigger-than
を選択すると、例えば10M以上のファイルをすべてパージします:git filter-repo --strip-blobs-bigger-than 10M
より多くの例と完全なドキュメントは
git filter-repo
ドキュメント を参照してください。 -
-
内部参照を削除しようとしているため、どの内部参照を削除すべきかを知るためには、各実行によって生成される
commit-map
ファイルが必要です。git filter-repo
を実行するたびに新しいcommit-map
, がcommit-map
作成さcommit-map
れ、commit-map
前の実行のcommit-map
ものが上書きさcommit-map
れます。次のコマンドを使用して、各commit-map
ファイルをバックアップできます:cp filter-repo/commit-map ./_filter_repo_commit_map_$(date +%s)
git filter-repo
コマンドを実行するたびに、この手順とそれに続くすべての手順(リポジトリのクリーンアップ手順を含む)を繰り返してください。 -
変更を強制的にプッシュするには、ミラーフラグを解除する必要があります:
git config --unset remote.origin.mirror
-
変更を強制プッシュして GitLab 上のすべてのブランチを上書きします:
git push origin --force 'refs/heads/*'
ブランチが保護されていると、これは失敗します。ブランチの保護を解除してからプッシュし、保護されたブランチを再度有効にしてください。
-
タグ付きリリースから大きなファイルを削除するには、変更を GitLab のすべてのタグに強制プッシュしてください:
git push origin --force 'refs/tags/*'
タグが保護されていると、これは失敗します。続行するには、タグの保護を解除してプッシュし、保護されたタグを再度有効にする必要があります。
-
存在しなくなったコミットへのデッドリンクを防ぐには、
git filter-repo
によって作成されたrefs/replace
をプッシュしてください。git push origin --force 'refs/replace/*'
この仕組みについては、Git
replace
のドキュメントを参照ください。 - 次のステップに進む前に、少なくとも30分は待ちましょう。
- リポジトリのクリーンアップを実行します。この処理は、30分以上前のオブジェクトのみをクリーンアップします。詳細については、解放されない領域を参照してください。
リポジトリのクリーンアップ
リポジトリのクリーンアップでは、オブジェクトのテキストファイルをアップロードすると、GitLabがこれらのオブジェクトへのGit内部参照を削除します。git filter-repo
を使って、リポジトリのクリーンアップで使えるオブジェクトのリスト(commit-map
ファイル)を作成することができます。
GitLab 13.6で導入された、リポジトリを安全にクリーンアップするには、オペレーション中は読み取り専用にする必要があります。これは自動的に行われますが、書き込みが進行中であればクリーンアップリクエストの送信は失敗します。そのため、続行する前に未処理のgit push
オペレーションをキャンセルしてください。
リポジトリをクリーンアップするには
- リポジトリのプロジェクトに移動します。
- 設定 > リポジトリに移動します。
-
オブジェクトのリストをアップロードします。例えば、
filter-repo
ディレクトリにあるgit filter-repo
によって作成されたcommit-map
ファイルです。commit-map
ファイルが 250 KB または 3000 行を超える場合は、ファイルを分割してアップロードできます:split -l 3000 filter-repo/commit-map filter-repo/commit-map-
- クリーンアップを開始]を選択します。
これです:
- Git 内部での古いコミットへの参照を削除します。
-
git gc --prune=30.minutes.ago
をリポジトリに対して実行し、参照されていないオブジェクトを削除します。新しいパックファイルが作成されるまで古いパックファイルが削除されないため、一時的にリポジトリのサイズが大きくなります。 - プロジェクトにアタッチされている未使用の LFS オブジェクトのリンクを解除し、ストレージスペースを解放します。
- ディスク上のリポジトリのサイズを再計算します。
GitLab はクリーンアップが完了した後、再計算されたリポジトリサイズをメールで通知します。
リポジトリサイズが減らない場合は、過去30分間に行われた Git オペレーションで参照されたオブジェクトが残っていることが原因かもしれません。リポジトリが 30 分以上休止してから、この手順を再実行してみてください。
リポジトリのクリーンアップを使うときは、次のことに注意してください:
- プロジェクトの統計情報はキャッシュされます。ストレージ使用量の削減を確認するには、5~10分待つ必要があるかもしれません。
- クリーンアップでは、30分以上前の緩いオブジェクトが削除されます。つまり、過去30分間に追加または参照されたオブジェクトは、すぐには削除されません。Gitalyサーバーにアクセスできる場合は、この遅延をスキップして、
git gc --prune=now
を実行し、すべての緩いオブジェクトを直ちに削除することができます。 - この処理によって、GitLabのキャッシュやデータベースから書き換えられたコミットのコピーがいくつか削除されますが、カバレッジにはまだ多くのギャップがあり、コピーの一部はいつまでも残っている可能性があります。インスタンスキャッシュをクリアすることで、それらの一部を削除することができるかもしれませんが、セキュリティの観点からは依存すべきではありません!
ストレージの制限
リポジトリサイズの制限:
- 管理者が設定できます。
- セルフマネージドインスタンスで管理者が設定可能。
- GitLab.comに設定されています。
プロジェクトがサイズ制限に達した場合、プロジェクトを作成することはできません:
- プロジェクトにプッシュします。
- 新しいマージリクエストを作成します。
- 既存のマージリクエストをマージします。
- LFS オブジェクトをアップロードします。
まだできます:
- 新しいイシューの作成。
- プロジェクトをクローンします。
リポジトリサイズの制限を超える場合は、できます:
- 一部のデータを削除します。
- 新しいコミットを作成します。
- リポジトリにプッシュバックします。
これらのアクションでは不十分な場合は、以下の方法もあります:
- いくつかのブロブをLFSに移動します。
- いくつかの古い依存関係の更新を履歴から削除。
残念ながら、このワークフローはうまくいきません。なぜなら、以前のコミットやブロブはまだ存在しているからです。代わりに、履歴を書き換える必要があります。オープンソースのコミュニティメンテンドツールgit filter-repo
をお勧めします。
git gc
が GitLab 側で実行されるまでは、「削除された」コミットや blob はまだ存在しています。また、書き換えた履歴を GitLab にプッシュできなければなりませんが、すでにサイズの上限を超えている場合は不可能かもしれません。これらの制限を解除するには、自己管理 GitLab インスタンスの管理者が、制限を超えた特定のプロジェクトの制限を増やす必要があります。そのため、常に積極的に制限値を下回るようにしたほうがよいでしょう。リミットを超えてしまい、一時的にリミットを増やすことができない場合、唯一の選択肢となります:
- 現地で不要なものをすべて刈り込みます。
- GitLabで新しいプロジェクトを作成し、代わりにそれを使い始めましょう。
トラブルシューティング
GUIに表示されるリポジトリの統計が正しくない
表示されるサイズやコミット数がエクスポートされた.tar.gz
やローカルリポジトリと異なる場合、GitLab 管理者に強制更新を依頼することができます。
Rails コンソールを使用します:
p = Project.find_by_full_path('<namespace>/<project>')
pp p.statistics
p.statistics.refresh!
pp p.statistics
# compare with earlier values
# An alternate method to clear project statistics
p.repository.expire_all_method_caches
UpdateProjectStatisticsWorker.perform_async(p.id, ["commit_count","repository_size","storage_size","lfs_objects_size"])
# check the total artifact storage space separately
builds_with_artifacts = p.builds.with_downloadable_artifacts.all
artifact_storage = 0
builds_with_artifacts.find_each do |build|
artifact_storage += build.artifacts_size
end
puts "#{artifact_storage} bytes"
スペースが解放されません
このページで定義されているプロセスは、リポジトリのExporterのサイズを減少させることができますが、Web UIとターミナルの両方で、ファイルシステムの使用量は変更されません。
この処理では、多くの到達不可能なオブジェクトがリポジトリに残ります。それらは到達不可能なため、エクスポートには含まれませんが、ファイルシステムにはまだ保存されています。これらのファイルは、2週間の猶予期間の後に刈り込まれます。プルーニングによってこれらのファイルが削除され、ストレージ使用量の統計が正確になります。
このプロセスを迅速化するには、「到達不能オブジェクトの刈り込み」ハウスキーピングタスクを参照してください。