gitによって作成された大きな.packファイルを削除する


112

大量のファイルをブランチにチェックインしてマージし、その後それらを削除する必要がありました。今では、取り除く方法がわからない大きな.packファイルが残っています。

を使用してすべてのファイルを削除git rm -rf xxxxxxし、--cachedオプションも実行しました。

現在次のディレクトリにある大きな.packファイルを削除する方法を誰かに教えてもらえますか?

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

まだ持っているがもう使用していないブランチを削除する必要があるだけですか?それとも、実行する必要がある何か他にありますか?

どれほどの違いがあるのか​​はわかりませんが、ファイルに対して南京錠が表示されています。

ありがとう


編集する

これが私のbash_historyからの抜粋です。この状態にどうやって移行できたかがわかります(この時点で、「my-branch」というgitブランチで作業していて、さらに多くのフォルダーを含むフォルダーがあるとします/ファイル):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

私も以下を実行したと思いましたが、他の人と一緒にbash_historyに表示されません:

git rm -rf --cached unwanted_folder/

またgit gc、パックファイルを整理するためにいくつかのgitコマンド(など)を実行したと思いましたが、.bash_historyファイルにも表示されません。


それらを削除した方法を明確にできますか?それらがまだコミット履歴にある場合、それらはまだパックファイルにあります。
loganfsmyth

こんにちは@loganfsmyth、私はうまくいけば役立つbash履歴スクリプトを追加しました。
user1116573 2012年

回答:


201

問題は、ファイルを削除しても、以前のリビジョンに残っていることです。それがgitの要点です。何かを削除しても、履歴にアクセスすることでそれを取り戻すことができます。

あなたが何をしようとしているのかは履歴の書き換えと呼ばれ、それはgit filter-branchコマンドを含んでいました。

GitHubは彼らのサイトで問題の良い説明をしています。https://help.github.com/articles/remove-sensitive-data

より直接質問に答えるために、基本的に実行する必要があるのは、unwanted_filename_or_folderそれに応じて置き換えられたこのコマンドです。

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

これにより、リポジトリへのアクティブな履歴からファイルへのすべての参照が削除されます。

次のステップでは、GCサイクルを実行して、ファイルへのすべての参照を強制的に期限切れにし、packfileから削除します。これらのコマンドでは、何も置き換える必要はありません。

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
私はそれが将来この質問に来る人にとって簡単になる場合は受け入れられたものとしてマークしましたが、私は実際にその時点で新しいgitリポジトリを作成して問題を解決しました
user1116573

3
どうやってこれを思いついたのかわかりませんが… ありがとう。
エゼキエルビクター

5
この答えは私を正しい方向に向けました。しかし、実際にファイルを削除するには、さらに3つのコマンドが必要です 1)git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2)git reflog expire --expire=now --all3)git gc --prune=now
arod

3
私はbfgはるかに使いやすいと思います。また、公式githubのドキュメントで推奨されています:help.github.com/articles/...
ティモが

2
@Timo時間の経過とともに状況が変化した場合は、新しい回答を追加することをお勧めします。頑張れ!
loganfsmyth

12

シナリオA:大きなファイルがブランチにのみ追加された場合、を実行する必要はありませんgit filter-branch。ブランチを削除してガベージコレクションを実行するだけです。

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

シナリオB:ただし、bashの履歴に基づいて、変更をマスターにマージしたようです。(git pushまだ)誰とも変更を共有していない場合。最も簡単なのは、大きなファイルのあるブランチとマージする前にマスターをリセットすることです。これにより、ブランチからのすべてのコミットと、マージ後にマスターに対して行われたすべてのコミットが削除されます。したがって、大きなファイルに加えて、実際に望んでいた変更が失われる可能性があります。

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

次に、シナリオAの手順を実行します。

シナリオC:マージした後に保持したいブランチからのその他の変更またはマスターの変更があった場合、マスターをリベースし、必要なコミットを選択的に含めるのが最善です。

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

エディターで、大きなファイルを追加したコミットに対応する行を削除し、その他はすべてそのままにします。保存して終了します。マスターブランチには必要なものだけを含め、大きなファイルは含めないでください。をgit rebase使用-pすると、マージコミットが削除されるため、後にmasterの線形履歴が残ることに注意してください<commit hash>。これはおそらくあなたにとっては大丈夫ですが、そうでない場合は、で試すことができますが-pgit help rebaseと言いcombining -p with the -i option explicitly is generally not a good idea unless you know what you are doingます。

次に、シナリオAのコマンドを実行します。


ここにはシナリオAのバリアントがありますが、予期しない追加の問題があります。

シナリオ大量の一時パックファイルを削除するという、地雷の問題を解決しました。リポジトリはビルドサーバーによって管理されていたため、.git / objects / packフォルダー内に不要なファイルが作成されていました。ディスクから貴重なGBを解放することができました。
xrissz

7

loganfsmythが彼の回答ですでに述べたように、ファイルをリポジトリから削除した後でもそこに存在し続けるため、git履歴を消去する必要があります。公式GitHubドキュメントはBFG推奨していますfilter-branch

履歴からファイルを削除する

彼らのウェブサイトからBFGをダウンロードしてください。Javaがインストールされていることを確認し、ミラークローンを作成して履歴を削除します。YOUR_FILE_NAME削除するファイルの名前に置き換えてください:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

フォルダを削除する

上記と同じですが、 --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

別のオプション

BFGは、次のようなさらに洗練されたオプション(docsを参照)も許可します。

100Mより大きいすべてのファイルを履歴から削除します。

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

重要!

BFGを実行するときは、両方YOUR_FILE_NAMEYOUR_FOLDER_NAME実際にファイル/フォルダー名だけであることに注意してください。それらはパスはないので、などfoo/bar.jpgは機能しません!代わりに、指定された名前のすべてのファイル/フォルダーは、存在するパスやブランチに関係なく、リポジトリの履歴から削除されます。


このbfgツールをローカルのGitリポジトリに適用したいのですが、コマンドは次のようになりますか?
Angel Todorov、

5

1つのオプション:

git gc手動で実行して、多数のパックファイルを1つまたはいくつかのパックファイルに圧縮します。この操作は永続的です(つまり、大きなパックファイルは圧縮動作を保持します)。git gc --aggressive

別のオプションは、コードと.gitをどこかに保存してから.gitを削除し、この既存のコードを使用してやり直して、新しいgitリポジトリを作成することです(git init)。


こんにちはマイケル、私は実行git gcしていくつかのパックファイルに取り掛かりましたが、大きいファイルはまだその1つであり、それを取り除き、外部でフォルダーをより簡単にバックアップできるようにします(以前のzipは1でした) -2Mb、現在は55Mb)。誰かが何か他のことを提案できない限り、私は新鮮なgitを作成する必要があるかもしれないと思います。これは、現在持っているブランチなどにアクセスできなくなることを意味すると思います...?
user1116573

2
私はあきらめて、.gitフォルダを削除して、あなたが言ったように新しいgitリポジトリを作成しました。私はそれを教訓と考えます。マイケルに感謝します。
user1116573

4
これはあまり意味がありません。どうしてgitに現在のリポジトリを統合し、その過程でパックファイルを削除するように指示できないのですか?
jml

4

次のコマンドを実行PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAし、ファイル名だけでなく、削除するファイルのパスに置き換えます。これらの引数は:

  1. すべてのブランチとタグの履歴全体をGitに処理しますが、チェックアウトはしません。
  2. 指定されたファイルと、結果として生成された空のコミットを削除します
  3. 既存のタグを上書きする
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

これにより、リポジトリへのアクティブな履歴からファイルへのすべての参照が強制的に削除されます。

次のステップでは、GCサイクルを実行して、ファイルへのすべての参照を強制的に期限切れにし、パックファイルから削除します。これらのコマンドでは、何も置き換える必要はありません。

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

最後に、第2部から、28Gのレポを158Mまで取得しました。Googleの他のほとんど何も働いていません。ありがとうございました。
Sridhar Sarnobat

上記の手順に従い、「git push origin --force --all」としてプッシュしましたが、リモートブランチ(マスター、開発、機能/ ASD-1010)はクリーンアップされませんでした。リモートリポジトリからクローンを作成したとき、.packファイルがまだ存在していました。このクリーンアップをすべてのリモートgitブランチに反映するにはどうすればよいですか?
Sambit Swain

1

私はショーに少し遅れますが、上記の回答でクエリが解決されない場合は、別の方法を見つけました。特定の大きなファイルを.packから削除するだけです。大きな2GBファイルを誤ってチェックインしてしまうという問題がありました。私はこのリンクで説明されている手順に従いました:http : //www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


この方法を実行すると、プロジェクトの履歴全体が完全に削除されるか、指定されたファイルのみが削除されます。
Samim Aftab Ahmed

-3

これはコーディングよりも便利なソリューションです。ファイルを圧縮します。zipをファイルビュー形式で開きます(解凍とは異なります)。.packファイルを削除します。フォルダを解凍して置き換えます。魅力的な作品!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.