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 スイートの一部です。

Remember, after you rewrite the history, whether you use the BFG or filter-branch, you will need to remove reflog entries that point to old history, and finally run the garbage collector to purge the old data. 

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 による履歴書き換え(代替方法)

The filter-branch command rewrites a Git repo's revision history, just like the BFG, but the process is slower and more manual. If you don't know where the big file is, your first step will be to find it:

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

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. List the big files in your repo by running the git_find_big.sh script.

    $ 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

    The big files are all JAR files.  The pack size column is the most relevant.  The aui-dependencies.jar compacts to 169KB  but the emojis.jar compacts only to 580.  The emojis.jar is a candidate for removal.

filter-branch を実行する

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

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

The --index-filter option modifies a repo's staging (or index). The --cached option removes a file from the index not the disk.  This is faster as you don't have to checkout each revision before running the filter.  The --ignore-unmatch option in git rm prevents the command from failing if the pathname it is trying to remove isn't there.  By specifying a commit HASH, you remove the pathname from every commit starting with the HASH on up.  To remove from the start, leave this off or you can specify HEAD.  

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

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

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

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

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
  2. 残りの大規模ファイルごとに、手順 1 を繰り返します。
  3. Update the references in your repository. filter-branch creates backups of your original refs namespaced under refs/original/. Once you're confident that you deleted the correct files, you can run the following command to delete the backed up refs, allowing the large objects to be garbage collected:

    $ 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.