Git リポジトリのメンテナンス

このページの内容

お困りですか?

アトラシアン コミュニティをご利用ください。

コミュニティに質問

Git リポジトリのメンテナンスには一般的に、リポジトリ サイズの縮小が含まれます。他のバージョン管理システムからインポートした場合、インポート後に不要なファイルをクリーンアップする必要がある場合があります。ここでは、Git リポジトリからの大きなファイルの削除について、および、以下のトピックについて説明します。

注意

このページの手順は、破壊的な操作を含む高度なテクニックを使用しています。内容を注意深く確認し、開始前にリポジトリのバックアップを行うようにしてください。バックアップを作成する最も簡単な方法は、--mirror フラグを使用してリポジトリをクローンし、クローン全体を圧縮するやり方です。バックアップがあれば、メンテナンス中にリポジトリの主要なエレメントを誤って破損してしまっても、回復することができます。

リポジトリ ユーザーにとって、メンテナンスは破壊的になる可能性があることに注意する必要があります。リポジトリをメンテナンスすることについて、チームまたはリポジトリのフォロワーに伝えることをおすすめします。全員がコードをチェックイン済みで、メンテナンス中は開発を一時停止することに合意していることを確認してください。

Git リポジトリからのファイル削除について理解する

リポジトリをクローンすると、全ソースコード ファイルのすべてのバージョンを含め、履歴全体のクローンが作成されます。ユーザーが JAR など大きいファイルをコミットすると、後から作成するすべてのクローンにこのファイルが含まれます。後のコミットでプロジェクトからこのファイルを削除したとしても、ファイルは依然としてリポジトリ履歴内に存在します。このファイルをリポジトリから削除するには、次の作業が必要です。

  • プロジェクトの現在のファイルツリーからファイルを削除する
  • リポジトリ履歴からファイルを削除する - Git 履歴を書き換え、履歴を含むすべてのコミットをファイルから削除する
  • 古いコミット履歴を参照する reflog 履歴をすべて削除する
  • リポジトリをリパックし、git gc を使用して、現在は使用していないデータをガーベジコレクトする

Git 「GC」(ガベージ コレクション)は、どのブランチやタグも実際に使用せず、何らの参照もしていないすべてのデータをリポジトリから削除します。ガベージ コレクションを有効にするには、不要ファイルを含むリポジトリ履歴をすべて書き換えて、不要ファイルを参照しないようにする必要があります。これで git gc は現在使用されていないデータを破棄できるようになります。

リポジトリの履歴書き換えは慎重を要する作業です。というのは、すべてのコミットがその親に依存し、どんな小さな変更であっても、以降のすべてのコミットのコミット ID を変更するためです。この作業用に 2 つの自動化ツールが利用できます。

  1. BFG Repo Cleaner - 処理が速く、シンプルで使いやすい。Java 6 以上が必要です。
  2. git filter-branch - 強力ではあるが、設定が難しく、規模の大きいリポジトリの場合、処理が遅い。 コア Git スイートの一部です。

BFG を使用するにしても、filter-branch を使用するにしても、履歴を書き換えたあと、古い履歴をポイントする reflog エントリーを削除し、最終的にはガベージ コレクタを実行して、古いデータを削除する必要があります。 

BFG による履歴の書き換え

BFG は大規模ファイルやパスワードなど、不要なデータを Git リポジトリから削除することを目的とする特別のツールで、(現在のコミットに含まれない)サイズの大きい履歴を簡単に削除する「--strip-blobs-bigger-than」フラグを備えています。

$ java -jar bfg.jar --strip-blobs-bigger-than 100M

(BFG により最新のコンテンツが保護されているため、最新 のコミットに含まれない) サイズが 100MB 以上のファイルは Git リポジトリの履歴から削除されます。必要であれば、ファイル名による指定も可能です。

$ java -jar bfg.jar --delete-files *.mp4

BFG は git filter-branch より 10 倍~ 1000 倍速く、一般的にずっと使いやすいツールです。詳細については、詳しい使用方法使用例を確認してください。

git filter-branch による履歴書き換え(代替方法)

filter-branch コマンドは BFG と同様に Git リポジトリの改訂履歴を書き換えますが、処理速度が遅く手作業も増えます。大きいファイルの場所がわからない場合、まずそれを見つける必要があります。

手作業によってリポジトリ内の大規模ファイルを確認する

Antony Stubbs はこの作業を効率的に実行する BASH スクリプトを書きました。 このスクリプトはパックファイルの内容を調べ、大規模ファイルを一覧表示します。ファイルの削除を開始する前に、次の操作を行い、このスクリプトを入手してインストールします。

  1. ローカル システムにスクリプトをダウンロードします。
  2. Git リポジトリにアクセス可能な、既知の場所にスクリプトを置きます。
  3. スクリプトを実行可能にします。

    $ chmod 777 git_find_big.sh
  4. ローカルシステムにリポジトリのクローンを作成します。
  5. リポジトリのルート ディレクトリに移動します。
  6. Git ガベージコレクタを手動で実行します。

    git gc --auto
  7. .git フォルダーのサイズを調べます。

    $ du -hs .git/objects
    45M	.git/objects 

    あとで参照するために、このサイズを書きとめます。

  8. git_find_big.sh スクリプトを実行して、リポジトリ内の大規模ファイルを一覧表示します。

    $ git_find_big.sh 
    All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file.
    size pack SHA location
    592 580 e3117f48bc305dd1f5ae0df3419a0ce2d9617336 media/img/emojis.jar
    550 169 b594a7f59ba7ba9daebb20447a87ea4357874f43 media/js/aui/aui-dependencies.jar
    518 514 22f7f9a84905aaec019dae9ea1279a9450277130 media/images/screenshots/issue-tracker-wiki.jar
    337 92 1fd8ac97c9fecf74ba6246eacef8288e89b4bff5 media/js/lib/bundle.js
    240 239 e0c26d9959bd583e5ef32b6206fc8abe5fea8624 media/img/featuretour/heroshot.png

    大規模ファイルはすべて JAR ファイルです。圧縮サイズ欄が最も重要です。aui-dependencies.jarは 169KB に圧縮されますが、emojis.jar は 580KB にしか圧縮されません。emojis.jar が削除の候補です。

filter-branch を実行する

このコマンドに、Git インデックス書き換え用のフィルターを渡すことができます。たとえば、あるフィルターはすべてのインデックス済みコミットからファイルを削除します。このコマンドの構文は次のとおりです。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch pathname' commitHASH

--index-filter オプションは、リポジトリのステージング (またはインデックス) を変更します。--cached オプションは、ディスクではなくインデックスからファイルを削除します。フィルターを実行する前に各リビジョンをチェックアウトする必要がないため、この方が速くなります。git rm の --ignore-unmatch オプションは、削除しようとしている pathname が存在しない場合にコマンドが失敗するのを防ぎます。commit HASH を指定することにより、この HASH 値以上のあらゆるコミットから pathname を削除します。最初から削除するには、この指定をオフにするか、HEAD を指定します。  

大規模ファイルが別々のブランチにある場合は、ファイルごとに名前を指定して削除する必要があります。すべてのファイルが 1 つのブランチ内にある場合は、ブランチ自体を削除します。

オプション 1: 名前を指定してファイルを削除する

以下の手順により、大規模ファイルを削除します。

  1. 次のコマンドを実行し、特定した最初の大規模ファイルを削除します。

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
  2. 残りの大規模ファイルごとに、手順 1 を繰り返します。
  3. リポジトリ内の参照を更新します。filter-branch は、refs/original/ 以下に名前空間を指定して、オリジナル参照のバックアップを作成します。 正しくファイルが削除されたことを確認できたら、次のコマンドを実行して、バックアップされた参照を削除することにより、大規模オブジェクトがガベージ コレクトされます。

    $ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

オプション 2: ブランチのみを削除する

すべての大規模ファイルが 1 つのブランチ内にある場合は、ブランチを削除するだけですみます。ブランチの削除により、すべての参照が自動的に削除されます。

  1. ブランチを削除します。

    $ git branch -D PROJ567bugfix
  2. 削除したブランチからの無効な reflog 参照のすべてを削除します。

    $ git reflog expire --expire=now PROJ567bugfix

不要データのガベージ コレクト

  1. (1 つのブランチのみを明示して作業している場合を除き)現在削除ずみのデータからの無効な reflog 参照をすべて削除します。

    $ git reflog expire --expire=now --all
  2. ガベージコレクタを実行し、古いオブジェクトを削除して、リポジトリをリパックします。

    $ git gc --prune=now
  3. すべての変更を Bitbucket リポジトリにプッシュバックします。

    $ git push --all --force
  4. タグもすべてカレントであることを確認します。

    $ git push --tags --force

 

 

最終更新日 2017 年 1 月 18 日

この内容はお役に立ちましたか?

はい
いいえ
この記事についてのフィードバックを送信する
Powered by Confluence and Scroll Viewport.