Gitリポジトリのコミット履歴から大きなファイルを削除/削除する方法は?


708

たまに、DVDリッピングをWebサイトのプロジェクトに落とし込んだ後、不注意に落としgit commit -a -m ...たり、ザップをしたりして、リポジトリが2.2ギグ膨らみました。次回、編集、ビデオファイルの削除、すべてのコミットを行いましたが、圧縮ファイルはリポジトリの履歴に残っています。

私はそれらのコミットからブランチを開始し、あるブランチを別のブランチにリベースできることを知っています。しかし、大きなファイルが履歴に表示されず、ガベージコレクション手順でクリーンアップされるように、2つのコミットをマージするにはどうすればよいですか?


9
この記事は、help.github.com / removing
MBOを


1
大きなファイルがサブディレクトリにある場合は、完全な相対パスを指定する必要があることに注意してください。
ヨハン


以下の多くの回答はgit filter-branch、BFGをよりも簡単だと宣伝していますが、私はその逆が真であることを発見しました。
2540625

回答:


605

Git履歴から不要なファイルを削除するために特別に設計された、BFG Repo-Cleanerを使用しgit-filter-branchます。

使用方法の指示に注意深く従ってください、コア部分はこれだけです:

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

サイズが100MBを超えるファイル(最新のコミットにないもの)は、Gitリポジトリの履歴から削除されます。次に、を使用git gcして、死んだデータを削除できます。

$ git gc --prune=now --aggressive

BFGは通常、を実行する場合よりも少なくとも10倍から50倍高速git-filter-branchで、一般的に使いやすくなっています。

完全な開示:私はBFG Repo-Cleanerの作成者です。


4
@tony複製とクリアの手順全体を繰り返して、再度プルするように求めるメッセージが表示されるかどうかを確認することは価値がありますが、リモートサーバーが非早送り更新を拒否するように構成されている(つまり、停止するように構成されている)ためです。歴史を失うことから-これはまさにあなたがしたいことです)。リモートでその設定を変更するか、失敗して、更新されたリポジトリの履歴を新しい空のリポジトリにプッシュする必要があります。
Roberto Tyley 14

1
@RobertoTyleyありがとう。私は3回試しましたが、すべて同じメッセージが表示されました。したがって、リモートサーバーが非早送りの更新を拒否するように構成されていることも正しいと思います。更新されたリポジトリを真新しいリポジトリにプッシュすることを検討します。ありがとうございました!
トニー

7
@RobertoTyleyパーフェクト、私の時間を節約してくれてありがとう。ちなみに、おそらくgit push --forceあなたの手順の後に行う必要があります。そうしないと、リモートリポジトリはまだ変更されません。
li2 2015

3
+1して追加しgit push --forceます。また、注目に値します:強制プッシュはリモートでは許可されない場合があります(gitlab.comではデフォルトで許可されていません。ブランチの「保護を解除」する必要がありました)。
MatrixManAtYrService

25
ツールが出力するトランプの専門用語は少し多いと思います。
クリス

564

他の開発者に履歴を公開している場合、あなたがしたいことは非常に破壊的です。履歴を修復した後に必要な手順についてはgit rebaseドキュメントの「アップストリームリベースからの回復」を参照してください。

少なくとも2つのオプションがあります。1つgit filter-branchはインタラクティブリベースで、どちらも以下で説明します。

使用する git filter-branch

Subversionインポートからのかさばるバイナリテストデータで同様の問題があり、gitリポジトリからのデータの削除について書いています

あなたのgit履歴が次のとおりだとしましょう:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

git lola非標準が、非常に便利な別名です。では--name-statusスイッチ、我々はそれぞれのコミットに関連付けられたツリーの変更を見ることができます。

「Careless」コミット(SHA1オブジェクト名はce36c98)では、ファイルoops.isoは誤って追加され、次のコミットcb14efdで削除されたDVDリップです。前述のブログ投稿で説明されている手法を使用すると、実行するコマンドは次のとおりです。

git filter-branch --prune-empty -d /dev/shm/scratch \
  --index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
  --tag-name-filter cat -- --all

オプション:

  • --prune-emptyフィルター操作の結果として空になった(つまり、ツリーを変更しない)コミットを削除します。典型的なケースでは、このオプションはより明確な履歴を生成します。
  • -dフィルタリングされた履歴の構築に使用する、まだ存在していない一時ディレクトリを指定します。最新のLinuxディストリビューションで実行している場合、でツリーを/dev/shm指定すると、実行が速くなります。
  • --index-filterメインイベントであり、履歴の各ステップでインデックスに対して実行されます。oops.iso見つかった場所はどこでも削除したいが、すべてのコミットに存在するわけではない。このコマンドgit rm --cached -f --ignore-unmatch oops.isoはDVD-ripが存在する場合はそれを削除し、それ以外の場合は失敗しません。
  • --tag-name-filterタグ名を書き換える方法を説明します。のフィルターcatは、アイデンティティー操作です。上記のサンプルのように、リポジトリにはタグがない可能性がありますが、完全な一般性のためにこのオプションを含めました。
  • -- オプションの終わりを指定します git filter-branch
  • --all以下--はすべての参照の省略形です。上記のサンプルのように、リポジトリには参照(マスター)が1つしかない場合がありますが、このオプションは一般性を高めるために含めました。

いくつかの攪拌の後、歴史は今です:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A   login.html
| * cb14efd Remove DVD-rip
| | D   oops.iso
| * ce36c98 Careless
|/  A   oops.iso
|   A   other.html
|
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

新しい「Careless」コミットは追加されるだけでother.htmlあり、「Remove DVD-rip」コミットはマスターブランチには存在しないことに注意してください。ラベルrefs/original/refs/heads/masterが付けられたブランチには、ミスをした場合の元のコミットが含まれています。削除するには、「リポジトリを縮小するためのチェックリスト」の手順に従ってください

$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now

より簡単な方法として、不要なビットを破棄するためにリポジトリを複製します。

$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo

file:///...クローンURL を使用すると、ハードリンクのみを作成するのではなく、オブジェクトをコピーします。

今あなたの歴史は:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

フィルター操作でこれらのコミットが変更されなかったため、最初の2つのコミット(「インデックス」と「管理ページ」)のSHA1オブジェクト名は同じままでした。「Careless」が失われoops.iso、「Login page」が新しい親を取得したため、SHA1 変更されました。

インタラクティブなリベース

の歴史を持つ:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

oops.iso追加したことがないかのように「Careless」から削除したい場合、「Remove DVD-rip」は役に立たない。したがって、インタラクティブなリベースに入る私たちの計画は、「管理ページ」を維持し、「注意せず」を編集して、「DVDリップの削除」を破棄することです。

実行$ git rebase -i 5af4522すると、以下の内容でエディターが起動します。

pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

計画を実行し、それを次のように変更します。

edit ce36c98 Careless
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
# ...

つまり、「Remove DVD-rip」で行を削除し、「Careless」の操作をeditではなくに変更しますpick

エディターを保存して終了すると、コマンドプロンプトに次のメッセージが表示されます。

Stopped at ce36c98... Careless
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

メッセージが示すように、私たちは編集したい「Careless」コミットを実行しているので、2つのコマンドを実行します。

$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue

1つ目は、問題のあるファイルをインデックスから削除します。2番目は、「Careless」を更新されたインデックスになるように変更または修正し-C HEAD、古いコミットメッセージを再利用するようにgitに指示します。最後に、git rebase --continue残りのリベース操作に進みます。

これはの歴史を与えます:

$ git lola --name-status
* 93174be (HEAD, master) Login page
| A     login.html
* a570198 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

あなたが望むのはそれです。


4
git filter-branchを使用しているときにプッシュできない理由、いくつかの参照を 'git@bitbucket.org:product / myproject.git'にプッシュできませんでした履歴が失われるのを防ぐために、非早送りの更新は拒否されましたリモートのマージもう一度押す前に変更します。
Agung Prasetyo 2013

11
コマンドに-f(または--force)オプションを追加git pushします。このフラグはチェックを無効にします。これにより、リモートリポジトリのコミットが失われる可能性があります。注意して使用してください。」
グレッグベーコン

5
これは、履歴から不要な大きなファイルを削除するためのgit-filter-branchの使用を説明する素晴らしく完全な回答ですが、Gregが彼の回答を書いて以来、BFG Repo-Cleanerがリリースされたことは注目に値します。使用-詳細については私の回答を参照してください。
Roberto Tyley 2014年

1
上記のいずれかの手順を実行した後、リモートリポジトリ(GitHub上の)で大きなファイルが削除されません。ローカルだけが行います。プッシュとナダを強制します。何が欠けていますか?
アザタール2014年

1
これはdirsでも機能します。... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop 2014

198

このシンプルで強力なコマンドを使用してみませんか?

git filter-branch --tree-filter 'rm -f DVD-rip' HEAD

この--tree-filterオプションは、プロジェクトの各チェックアウト後に指定されたコマンドを実行し、結果を再コミットします。この場合、DVD-ripというファイルが存在するかどうかに関係なく、すべてのスナップショットから削除します。

巨大なファイルを導入したコミット(35dsa2など)がわかっている場合は、HEADを35dsa2..HEADに置き換えて、あまりにも多くの履歴を書き直さないようにして、まだプッシュしていない場合にコミットが発散するのを回避できます。@ alpha_989の厚意によるこのコメントは、ここでは省略するには重要すぎるようです。

このリンクを参照してください


3
これは良い解決策です!ファイルを一覧表示するPythonスクリプトと、クリーンアップ
punkdata

5
bfgよりもはるかに優れています。bfgを使用してgitからファイルをクリーンアップできませんでしたが、このコマンドは
役に立ち

4
これは素晴らしい。大きなファイルが複数のブランチにある場合は、ブランチごとにこれを行う必要があるという他の人への注意事項。
ジェームズ

2
Windows では、の代わりにfatal: bad revision 'rm'を使用して修正しました。全体のコマンド:"'git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
marcotama

2
あなたが知っていればcommitあなたが(と言うにファイルを置く場所35dsa2)、あなたは置き換えることができHEAD35dsa2..HEAD。その方法tree-filterよりもはるかに遅いですがindex-filter、すべてのコミットをチェックアウトして書き直そうとはしません。HEADを使用すると、それを実行しようとします。
alpha_989 2018年

86

(この問題に対して私が見た最良の答えは次のとおりです:https : //stackoverflow.com/a/42544963/714112、ここにコピーされます。このスレッドはGoogle検索ランキングで上位に表示されますが、他のスレッドはそうではありません)

shell非常に高速なシェルワンライナー🚀

このシェルスクリプトは、リポジトリ内のすべてのblobオブジェクトを最小から最大にソートして表示します。

私のサンプルリポジトリでは、ここにある他のリポジトリよりも約100倍速く実行されました。
私の信頼できるAthlon II X4システムでは、5,622,155個のオブジェクトを持つLinuxカーネルリポジトリ1分強で処理します。

基本スクリプト

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort --numeric-sort --key=2 \
| cut --complement --characters=13-40 \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

上記のコードを実行すると、次のような人間が読める形式の出力が得られます。

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

🚀ファイルの高速削除🚀

次に、ファイルを削除しabから到達可能なすべてのコミットからHEADこのコマンドを使用するとします。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD

3
リポジトリにタグがある場合は、フラグを追加して、--tag-name-filter cat対応する新しいコミットが書き換えられたときにタグを付け直すこともできますgit filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD(つまり、この関連回答を参照)
naitsirhc

3
Macの手順とその他の情報は、元のリンクされた投稿に表示されます
nruth

3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADコウモリの
作業指示書

私の好きな答え。mac osで使用するわずかな調整(gnuコマンドを使用)git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Florian Oswald

rev-listを使用したクールなスクリプトですが、エイリアスとしては機能しませんでした。
Robin Manoli

47

SOで事実上すべての答えを試した後、リポジトリの大きなファイルをすばやく削除して削除し、再び同期できるようにするこの宝石をようやく見つけました:http : //www.zyxware.com/articles/4027/how-to-delete -files-permanently-from-your-local-and-remote-git-repositories

CDをローカルの作業フォルダーに移動し、次のコマンドを実行します。

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all

FOLDERNAMEを、指定したgitリポジトリから削除するファイルまたはフォルダーに置き換えます。

これが完了したら、次のコマンドを実行してローカルリポジトリをクリーンアップします。

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

すべての変更をリモートリポジトリにプッシュします。

git push --all --force

これにより、リモートリポジトリがクリーンアップされます。


私にとっては魅力のように働きました。
Ramon Vasconcelos

3
これも私にとってはうまくいきました。リポジトリー上の特定のフォルダー(私の場合は、ファイルが大きすぎるフォルダーまたはGithubリポジトリーが含まれているフォルダー)を削除しますが、存在する場合はローカルファイルシステムに保持します。
skizzo

私のために働いた!混乱を招く可能性のある履歴が残っていません(誰かが今すぐクローンを作成する場合)。壊れたリンクや依存関係などを更新する計画があることを確認してください
ruoho ruotsi

38

これらのコマンドは私の場合に機能しました:

git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

上記のバージョンと少し異なります。

これをgithub / bitbucketにプッシュする必要がある人のために(私はこれをbitbucketでのみテストしました):

# WARNING!!!
# this will rewrite completely your bitbucket refs
# will delete all branches that you didn't have in your local

git push --all --prune --force

# Once you pushed, all your teammates need to clone repository again
# git pull will not work

4
上記とどう違うのですか?
アンディヘイデン

1
何らかの理由で、私の場合、mkljunバージョンはgitスペースを削減していません。すでにを使用して、インデックスからファイルを削除していますgit rm --cached files。グレッグベーコンの命題はより完全で、この鉱山とまったく同じですが、フィルターブランチを複数回使用している場合の--forceインデックスを逃しました。それの。
コスタノス2013年

1
これは本当に役に立ちましたが、以下の@ lfender6445の代わりにここではなく-fオプションを使用する必要がありました-rfgit rm --cached -rf --ignore-unmatch oops.isogit rm --cached -r --ignore-unmatch oops.iso
drstevok

10

このコマンドは非常に破壊的である可能性があることに注意してください。より多くの人がリポジトリで作業している場合、全員が新しいツリーをプルする必要があります。サイズを小さくすることが目的でない場合は、3つの中間コマンドは必要ありません。フィルターブランチは削除されたファイルのバックアップを作成し、長期間そこにとどまることができるためです。

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

11
自分に多大な苦痛を与えたくない限り、これらのコマンドを実行しないでください。それは私の元のソースコードファイルの多くを削除しました。(元の質問に従って)GITのコミット履歴からいくつかの大きなファイルを削除すると想定していましたが、このコマンドは元のソースコードツリーからファイルを完全に削除するように設計されていると思います(大きな違い!)。私のシステム:Windows、VS2012、Gitソース管理プロバイダー。
Contango 2012年

2
私はこのコマンドを使用しました:git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --allコードの最初のコマンドの代わりに
Kostanos


8

ツリー全体を処理するのではなく、コミットが最近のものであることがわかっている場合は、次のようにします。 git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD


7

私は偶然、自分のサイトの膨大な* .jpaバックアップを保存していたbitbucketアカウントでこれに遭遇しました。

git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all

MY-BIG-DIRECTORY問題のフォルダを参照して、履歴(タグを含む)を完全に書き換えます。

ソース:https : //web.archive.org/web/20170727144429/http : //naleid.com : 80 / blog / 2012 / 01 /17/ finding-and-purging-big-files-from-git-history/


1
この応答は私に役立ちましたが、回答のスクリプトにはわずかな問題があり、すべてのブランチで検索するわけではありません。しかし、リンクのコマンドはそれを完全に行いました。
Ali B

5

履歴から削除されます

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all

これは私に感謝しました!!
Sonja Brits

これは私の場合に機能します。私はあなたのマスターブランチでこれを実行します。
S.ドメン

4

私は基本的にこの答えにあったことをしました:https//stackoverflow.com/a/11032521/1286423

(履歴については、ここにコピーして貼り付けます)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

名前を変更したり移動したりするのが好きなので、うまくいきませんでした。したがって、いくつかの大きなファイルは名前が変更されたフォルダーにありtree、それらのファイルを指すオブジェクト内の参照のため、GCはそれらのファイルへの参照を削除できなかったと思います。それを本当に殺すための私の究極の解決策は、

# First, apply what's in the answer linked in the front
# and before doing the gc --prune --aggressive, do:

# Go back at the origin of the repository
git checkout -b newinit <sha1 of first commit>
# Create a parallel initial commit
git commit --amend
# go back on the master branch that has big file
# still referenced in history, even though 
# we thought we removed them.
git checkout master
# rebase on the newinit created earlier. By reapply patches,
# it will really forget about the references to hidden big files.
git rebase newinit

# Do the previous part (checkout + rebase) for each branch
# still connected to the original initial commit, 
# so we remove all the references.

# Remove the .git/logs folder, also containing references
# to commits that could make git gc not remove them.
rm -rf .git/logs/

# Then you can do a garbage collection,
# and the hidden files really will get gc'ed
git gc --prune --aggressive

リポジトリ(.git)が32MBから388KBに変更され、フィルターブランチでもクリーンアップできませんでした。


4

git filter-branchコミット履歴から巨大なファイルを削除するために使用できる強力なコマンドです。ファイルはしばらく保持され、Gitは次のガベージコレクションで削除します。以下は、コミット履歴からファイルを削除するプロセス全体です。安全のために、以下のプロセスは最初に新しいブランチでコマンドを実行します。結果が必要な場合は、実際に変更したいブランチにリセットします。

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master

2

Git Extensionsを使用します。これはUIツールです。これには、「大きなファイルを探す」という名前のプラグインがあり、リポジトリ内の大きなファイルを見つけて永久に削除することができます。

このツールを使用する前に「git filter-branch」を使用しないでください。「filter-branch」によって削除されたファイルを見つけることができないためです(「filter-branch」は、リポジトリパックファイルからファイルを完全に削除するわけではありません)。 。


この方法は、大規模なリポジトリの場合は非常に遅くなります。大きなファイルをリストするのに1時間以上かかりました。その後、ファイルを削除する場合、1時間後には、削除する最初のファイルの処理の3分の1しかありません。
kristianp 2017年

はい、遅いですが、動作します...何かもっと早く知っていますか?
2017年

1
使用していませんが、このページの別の回答のように、BFG Repo-Cleaner。
kristianp 2017年


2

このスレッドには非常に良い答えがありますが、その一方で、それらの多くは古くなっています。使用git-filter-branchするのは難しく、大きなリポジトリではひどく遅くなるため、使用は推奨されなくなりました。

git-filter-repo はるかに高速で使いやすいです。

git-filter-repoPythonスクリプトであり、github:https : //github.com/newren/git-filter-repoで入手できます

必要なファイルは1つだけです。Python3スクリプトgit-filter-repoです。PATH変数に含まれているパスにそれをコピーします。Windowsでは、スクリプトの最初の行を変更する必要がある場合があります(INSTALL.mdを参照)。システムにPython3をインストールする必要がありますが、これは大したことではありません。

最初に実行できます

git filter-repo --analyze

これは、次に行うことを決定するのに役立ちます。

DVD-ripファイルはどこでも削除できます。

 git filter-repo --invert-paths --path-match DVD-rip

フィルターリポジトリは本当に高速です。私のコンピュータでfilter-branchによって約9時間かかったタスクは、filter-repoによって4分で完了しました。filter-repoを使用すると、さらに多くの素晴らしいことができます。そのためのドキュメントを参照してください。

警告:リポジトリのコピーでこれを行ってください。filter-repoの多くのアクションは元に戻すことができません。filter-repoは、変更されたすべてのコミット(もちろん)とそのすべての子孫のコミットハッシュを最後のコミットまで変更します!


1

この問題が発生した場合git rm、ファイルは履歴に一度存在したことをgitが記憶しているため、十分ではありません。したがって、そのファイルへの参照が保持されます。

さらに悪いことに、ブロブへの参照はgitガベージコレクターによるスペースのクリーンアップを妨げるため、リベースも簡単ではありません。これには、リモート参照とreflog参照が含まれます。

git forget-blobこれらの参照をすべて削除しようとする小さなスクリプトをまとめ、次にgit filter-branchを使用してブランチ内のすべてのコミットを書き換えます。

blobが完全に参照git gcされなくなると、削除されます

使い方はかなり簡単git forget-blob file-to-forgetです。あなたはここでより多くの情報を得ることができます

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

Stack Overflowからの回答といくつかのブログエントリのおかげで、これをまとめました。彼らへのクレジット!


あなたは自作でこれを手に入れるべきです
Cameron E

0

以外のgit filter-branch(遅いが、純粋なgitの溶液)とBFG(簡単に、非常にパフォーマンス)、性能の良いフィルターに別のツールでもあります:

https://github.com/xoofx/git-rocket-filter

その説明から:

git-rocket-filterの目的はコマンドに似ていますがgit-filter-branch、次の独自の機能を備えています。

  • コミットとツリーの高速書き換え(x10からx100のオーダー)。
  • --keep(ファイルまたはディレクトリを保持する)を使用したホワイトリストと--removeオプションを使用したブラックリストの両方の組み込みサポート。
  • ツリーフィルタリングのための.gitignoreのようなパターンの使用
  • コミットフィルタリングとツリーフィルタリングの両方のための高速で簡単なC#スクリプト
  • ファイル/ディレクトリパターンごとのツリーフィルタリングでのスクリプトのサポート
  • マージコミットを含む、空の/変更されていないコミットを自動的にプルーニング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.