Gitのコミット履歴から大きなファイルを削除する
1. 概要
このチュートリアルでは、さまざまなツールを使用してgitリポジトリのコミット履歴から大きなファイルを削除する方法を学習します。
2. gitfilter-branchを使用する
これは最も一般的に使用される方法であり、コミットされたブランチの履歴を書き換えるのに役立ちます。
たとえば、プロジェクトフォルダ内に誤ってblobファイルをドロップし、それを削除した後も、git履歴にそのファイルがあることに気付いたとします。
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 9e87646 (HEAD -> master) blob file removed
* 2583677 blob file
* 34ea256 my first commit
次のコマンドを使用してツリーとそのコンテンツを書き換えることで、git履歴からblobファイルを削除できます。
$ git filter-branch --tree-filter 'rm -f blob.txt' HEAD
ここでは、 rm オプション
コマンドを実行した後のgitログは次のとおりです。
* 8f39d86 (HEAD -> master) blob file removed
* e99a81d blob file
| * 9e87646 (refs/original/refs/heads/master) blob file removed
| * 2583677 blob file
|/
* 34ea256 my first commit
HEADをコミット履歴のSHA1キーに置き換えて、書き換えを最小限に抑えることができます。
gitログには、削除されたファイルへの参照がまだ含まれています。 リポジトリを更新することで、参照を削除できます。
$ git update-ref -d refs/original/refs/heads/master
-d オプションは、古い値がまだ含まれていることを確認した後、指定された参照を削除します。
参照が変更されたことをリポジトリに記録する必要があります。
$ git reflog expire --expire=now --all
expire サブコマンドは、古い参照ログエントリを削除します。
最後に、リポジトリをクリーンアップして最適化する必要があります。
$ git gc --prune=now
–prune = now オプションは、年齢に関係なく、緩いオブジェクトを削除します。
コマンドを実行した後、ここにgitログがあります:
* 6f49d86 (HEAD -> master) my first commit
参照が削除されたことがわかります。
または、次を実行することもできます。
$ git filter-branch --index filter 'git rm --cached --ignore-unmatched blob.txt' HEAD
これはまったく同じように機能します ツリーフィルター、 ただし、インデックス、つまり作業ディレクトリのみを書き換えるため、より高速です。 サブコマンド –無視-比類のない プロジェクト内の他のコミットされたディレクトリにファイルがない場合にコマンドが失敗するのを防ぎます。
大きなファイルを削除する場合、2つの異なるコマンドを使用するこのアプローチは遅くなる可能性があることに注意してください。
3. git-filter-repoを使用する
別のアプローチは、git-filter-repoコマンドを使用することです。 これはサードパーティのアドオンであり、使用が簡単で、他のアプローチよりも高速です。 さらに、これはgitの公式ドキュメントで推奨されているソリューションです。
3.1. インストール
少なくともpython3>=3.5およびgit>=2.22.0が必要です。 一部の機能にはgit2.24.0以降が必要です。
Linuxマシンにgit-filter-repoをインストールします。 Windowsインストールガイドについては、ドキュメントを参照してください。
まず、次のコマンドを使用してpython-pipとgit-filter-repoをインストールします。
$ sudo apt install python3-pip
$ pip install --user git-filter-repo
または、以下のコマンドを使用してgit-filter-repoをインストールできます。
# Add to bashrc.
export PATH="${HOME}/bin:${PATH}"
mkdir -p ~/bin
wget -O ~/bin/git-filter-repo https://raw.githubusercontent.com/newren/git-filter-repo/7b3e714b94a6e5b9f478cb981c7f560ef3f36506/git-filter-repo
chmod +x ~/bin/git-filter-repo
3.2. ファイルの削除
コマンドを実行してgitログを確認しましょう:
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* ee36517 (HEAD -> master) blob.txt removed
* a480073 project folder
次のことは、リポジトリを分析することです。
$ git filter-repo --analyze
Processed 5 blob sizes
Processed 2 commits
Writing reports to .git/filter-repo/analysis...done.
これにより、リポジトリの状態に関するレポートのディレクトリが生成されます。 レポートはで見つけることができます
次に、オプション –path-match、を指定してこのコマンドを実行します。これは、フィルター処理された履歴に含めるファイルを指定するのに役立ちます。
$ git filter-repo --force --invert-paths --path-match blob.txt
これが私たちの新しいgitログです:
* 8940776 (HEAD -> master) project folder
実行後、変更されたコミットのコミットハッシュを変更します。
4. BRGレポクリーナーの使用
もう1つの優れたオプションは、Javaで記述されたサードパーティのアドオンである BRGRepo-Cleanerです。
200MBを超えるblobファイルを削除したいとします。 このアドオンを使用すると、これを簡単に行うことができます。
$ java -jar bfg.jar --strip-blob-bigger-than 200M my-repo.git
次に、このコマンドを実行して、デッドデータをクリーンアップしましょう。
$ git gc --prune=now --aggressive
5. git-rebaseを使用する
このアプローチを使用するには、gitログのSHA1キーが必要です。
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 535f7ea (HEAD -> master) blob file removed
* 8bffdfa blob file
* 5bac30b index.html
私たちの目的は、コミット履歴からblobファイルを削除することです。 したがって、削除するエントリの前にあるエントリの履歴からSHA1キーを使用します。
このコマンドを使用して、インタラクティブなリベースを開始します。
$ git rebase -i 5bac30b
これにより、 nano エディターが開き、次のように表示されます。
pick 535f7ea blob file removed
pick 8bffdfa blob file
# Rebase 5bac30b..535f7ea onto 535f7ea (2 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
ここで、「」というテキストを削除してこれを変更します。535f7eablobファイルを削除しました「。 これは、コミット履歴を変更し、以前に削除した履歴を削除するのに役立ちます。
次に、ファイルを保存してエディターを終了すると、ターミナルに次のメッセージが表示されます。
interactive rebase in progress; onto 535f7ea
Last command done (1 command done):
pick 535f7ea blob file removed
No commands remaining.
You are currently rebasing branch 'master' on '535f7ea'.
(all conflicts fixed: run "git rebase --continue")
最後に、リベース操作を続けましょう。
$ git rebase --continue
Successfully rebased and updated refs/heads/master.
次に、コミット履歴を確認できます。
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 5bac30b (HEAD -> master) index.html
このアプローチはgit-filter-repoほど高速ではないことに注意してください。
6. 結論
この記事では、gitリポジトリのコミット履歴から大きなファイルを削除するためのさまざまなアプローチを学びました。 また、gitのドキュメントによると、 git filter-repo が推奨されていることもわかりました。これは、他のアプローチに比べて高速で短所が少ないためです。