git / GitHubの履歴からフォルダーとその内容を削除する


318

私はGitHubアカウントのリポジトリで作業していましたが、これは私が偶然見つけた問題です。

  • いくつかのnpmパッケージがインストールされたフォルダーを持つNode.jsプロジェクト
  • パッケージはnode_modulesフォルダーにありました
  • そのフォルダーをgitリポジトリーに追加し、コードをgithubにプッシュしました(そのときのnpm部分については考えていませんでした)
  • そのフォルダーがコードの一部である必要はないことに気づきました
  • そのフォルダを削除してプッシュしました

その場合、gitリポジトリの合計サイズは約6 MBでしたが、実際のコード(そのフォルダーを除くすべて)は約300 KBでした。

最後に私が探しているのは、gitの履歴からそのパッケージフォルダーの詳細を取り除く方法です。そのため、誰かがそれをクローンした場合、実際のファイルのみが取得される6MBの履歴をダウンロードする必要はありません。最後のコミットの時点で300KBになります。

私はこれの可能な解決策を調べ、これらの2つの方法を試しました

Gistは、スクリプトを実行した後、そのフォルダーを削除したことを示し、その後、50の異なるコミットが変更されたことを示したように機能するように見えました。しかし、そのコードをプッシュすることはできませんでした。私がそれをプッシュしようとしたとき、それは言いましBranch up to dateたが、50のコミットがに変更されたことを示しましたgit status。他の2つの方法も役に立ちませんでした。

そのフォルダーの履歴が削除されたことが示されていても、ローカルホストでそのリポジトリのサイズを確認したところ、まだ約6MBでした。(私もrefs/originalフォルダーを削除しましたが、リポジトリのサイズの変更を確認できませんでした)。

私が明確にしたいのは、コミット履歴(これが私が起こったと思う唯一のことです)だけでなく、gitがロールバックしたいと仮定しているそれらのファイルを取り除く方法があるかどうかです。

これに対する解決策が提示され、私のローカルホストに適用されているが、そのGitHubリポジトリに複製できない場合、そのリポジトリを複製し、最初のコミットにロールバックしてトリックを実行し、それをプッシュすることができます(つまり、gitがまだこれらすべてのコミットの履歴がありますか?-別名6MB)。

私のここでの最終目標は、基本的にgitからフォルダーの内容を削除する最良の方法を見つけることです。これにより、ユーザーは6MB相当のものをダウンロードする必要がなく、モジュールフォルダーに触れたことのない他のコミットも可能です(これはかなり良いことです)それらのほとんどすべて)gitの歴史の中で。

これどうやってするの?


3
以下の回答のいずれかで問題が解決した場合は、質問への回答としてそれを受け入れることを検討する必要があります。meta.stackexchange.com/questions/5234/...
starbeamrainbowlabs

最良の答えは次のとおりです。stackoverflow.com/a/32886427/5973334
Kuzeko

回答:


556

ここにコードをコピーして貼り付ける場合:

これはnode_modules履歴から削除する例です

git filter-branch --tree-filter "rm -rf node_modules" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force

gitが実際に行うこと:

最初の行は--tree-filter、HEAD(現在のブランチ)と同じツリー()上のすべての参照を反復処理し、コマンドを実行しrm -rf node_modulesます。このコマンドは、node_modulesフォルダーを削除し(-r、なし-rrmは、フォルダーを削除しません)、ユーザーにプロンプ​​トを表示しません(-f)。追加された--prune-empty削除は、役に立たない(何も変更しない)コミットを再帰的に削除します。

2行目は、その古いブランチへの参照を削除します。

残りのコマンドは比較的単純です。


3
余談ですが、私は以前git count-objects -vにファイルが実際に削除されたかどうかを確認していましたが、リポジトリのクローンを再度作成するまで、リポジトリのサイズは同じままです。Gitは私が考えるすべての元のファイルのコピーを保持します。
Davide Icardi 2015

4
古代ではないgitの場合、これはおそらくで--force-with-leaseはなくと読む必要があり--forceます。
Griwes

4
これらのコマンドはいずれもWindowsでは機能しません。または、少なくともWindows 10では、「カットアンドペースト」が機能するOSを投稿してください
David

3
Windows 10ユーザーの場合、これはWindowsのBash(Ubuntuを使用)でうまく機能します
Andrej Kyselica '13

3
私はそれをWindowsシェルとgit bashで試してみましたが、うまくいきませんでした。最初のコマンドはパスし、2番目のコマンドは失敗します!
Mohy Eldeen 2017年

240

--tree-filter他の回答で使用されているオプションは、特に多くのコミットがある大きなリポジトリでは、非常に遅くなる可能性があることがわかりました。

--index-filterこれは、オプションを使用してgit履歴からディレクトリを完全に削除するために使用する方法です。

# Make a fresh clone of YOUR_REPO
git clone YOUR_REPO
cd YOUR_REPO

# Create tracking branches of all branches
for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

# Remove DIRECTORY_NAME from all commits, then remove the refs to the old commits
# (repeat these two commands for as many directories that you want to remove)
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch DIRECTORY_NAME/' --prune-empty --tag-name-filter cat -- --all
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

# Ensure all old refs are fully removed
rm -Rf .git/logs .git/refs/original

# Perform a garbage collection to remove commits with no refs
git gc --prune=all --aggressive

# Force push all branches to overwrite their history
# (use with caution!)
git push origin --all --force
git push origin --tags --force

次のコマンドを使用して、リポジトリの前後のサイズを確認できますgc

git count-objects -vH

3
これがはるかに速い理由を説明できますか?
knocte 2015年

7
@knocte:ドキュメントから(git-scm.com/docs/git-filter-branch)「--index-filter:...はツリーフィルターに似ていますが、ツリーをチェックアウトしないため、処理速度が大幅に向上します」
Lee Netherton

23
なぜこれは受け入れられない答えですか?それはとても徹底的です。
Mad Physicist

2
Windowsでこれを行う場合は、一重引用符ではなく二重引用符が必要です。
クリスモーネス2017

12
パッシング--quietgit rm4因子によって少なくとも上記のスピードアップ私の書き換え
ctusch

46

上記の一般的な回答に加えて、Windowsシステムに関する注意事項をいくつか追加します。コマンド

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
  • 変更せずに完璧に動作します!そのため、あなたはしてはならない使用Remove-Itemdelまたは何か他のものの代わりにrm -rf

  • ファイルまたはディレクトリへのパスを指定する必要がある場合は、次のようにスラッシュを使用します./path/to/node_modules


ディレクトリにが含まれている場合、これはWindowsでは機能しません。名前に(ドット)。
Corneliu Serediuc

4
そして、私は解決策を見つけました。「rm -rf node.modules」のようなrmコマンドには、二重逆コンマを使用します。
Corneliu Serediuc

23

私が見つけた最良かつ最も正確な方法は、bfg.jarファイルをダウンロードすることでした:https ://rtyley.github.io/bfg-repo-cleaner/

次に、コマンドを実行します。

git clone --bare https://project/repository project-repository
cd project-repository
java -jar bfg.jar --delete-folders DIRECTORY_NAME  # i.e. 'node_modules' in other examples
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror https://project/new-repository

ファイルを削除する場合は、代わりにdelete-filesオプションを使用します。

java -jar bfg.jar --delete-files *.pyc

1
非常に簡単:)あなたが唯一の特定のフォルダが削除されていることSHUREを作りたい場合は、この意志のヘルプ:stackoverflow.com/questions/21142986/...
emjay

9

これに最新の答えがであることを思わないで使うfilter-branch延期という仕事は、外部ツールに(少なくともgitの自体はもうそれを推奨していません)を直接、と。特に、現在git-filter-repoが推奨されています。そのツールの作成者は、直接使用すると問題が発生する理由についての議論提供filter-branchします。

dir履歴から削除する上記の複数行スクリプトのほとんどは、次のように書き直すことができます。

git filter-repo --path dir --invert-paths

どうやら、ツールはそれよりも強力です。作成者、電子メール、参照名などでフィルターを適用できます(完全なマンページはこちら)。さらに、それは速いです。インストールは簡単です。さまざまな形式で配布されています


素敵なツール!Ubuntu 20.04で正常に動作します。stdlib pip3 install git-filter-repoのみであり、依存関係をインストールしないためです。Ubuntu 18では、ディストリビューションのgitバージョンと互換性がありませんがError: need a version of git whose diff-tree command has the --combined-all-paths optiondocker run -ti ubuntu:20.04
kubanczyk

7

テスト後、コメントにコマンドを追加するだけで、コピー&ペーストのレシピを完成させます(コピー/ペーストソリューションの場合)。

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force

この後、.gitignoreから「node_modules /」という行を削除できます。


なぜ削除node_modulesするの.gitignoreですか?彼らが誤って再び犯される可能性があるように??
アダムスキー

1
gitignoreから削除されず、gitignoreに追加されます。コミットメッセージには、「gitignore」ではなく「git history」と表示されます:)
Danny Tuppeny

しかし、コメントには、node_modulesから削除できると記載されています.gitignore
zavr

7

Windowsユーザーの場合、別のバックアップがすでに存在する場合は、コマンドも強制的に 追加する"代わりに使用することに注意してください。'-f

git filter-branch -f --tree-filter "rm -rf FOLDERNAME" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo FOLDERNAME/ >> .gitignore
git add .gitignore
git commit -m "Removing FOLDERNAME from git history"
git gc
git push origin master --force

3

Windowsでgitを使用して、古いC#プロジェクトからbinおよびobjフォルダーを削除しました。に注意してください

git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD

gitインストールフォルダー内のusr / binフォルダーを削除することにより、gitインストールの整合性を破壊します。

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