リポジトリに無視する必要のあるファイルがいくつかあります。それらを.gitignoreに追加しましたが、もちろん、リポジトリから削除されません。
だから私の質問は、私の履歴を書き換えてこれらすべてのファイルを簡単に削除できるフィルターブランチを使用した魔法のコマンドまたはスクリプトはありますか?または、それらを削除するコミットを作成するコマンドですか?
それらをリポジトリから手動で削除できます。
git rm --cached file1 file2 dir/file3
または、ファイルがたくさんある場合:
git rm --cached `git ls-files -i -c --exclude-from=.gitignore`
しかし、これはWindowsのGitBashでは機能しないようです。エラーメッセージが表示されます。以下の方がうまく機能します。
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
Windows上のPowerShellでは、これはさらにうまく機能します(パスとファイル名のスペースを処理します)。
git ls-files -i -c --exclude-from=.gitignore | %{git rm --cached $_}
これらのファイルを使用せずに履歴全体を書き換えることに関しては、自動的にそれを行う方法があるかどうかは非常に疑わしいです。
そして、歴史を書き直すのは悪いことだということは誰もが知っていますね。:)
OSに関係なく機能する簡単な方法は、
git rm -r --cached .
git add .
git commit -m "Drop files from .gitignore"
基本的にすべてのファイルを削除して再度追加しますが、内のファイルgit add
は無視します.gitignore
。
この--cached
オプションを使用すると、ファイルシステムにファイルが保持されるため、ディスクからファイルを削除することはありません。
注:コメントの中で、すべてのファイルの履歴が失われるとの指摘もありました。MacOSでgit2.27.0を使用してこれをテストしましたが、そうではありません。何が起こっているかを確認したい場合はgit diff HEAD~1
、コミットをプッシュする前に確認してください。
.gitignore内のファイルは追跡されていないため、git cleanコマンドを使用して、バージョン管理されていないファイルを再帰的に削除できます。
git clean -xdn
ドライランを実行し、何が削除されるかを確認するために使用します。
次に、を使用git clean -xdf
して実行します。
基本的に、git clean -h
またはman git-clean
(UNIXでは)あなたに助けを与えるでしょう。
このコマンドは、ステージング領域にない新しいファイルも削除することに注意してください。
それが役に立てば幸い。
.gitignoreステートメントの出力をsedで操作することにより、非常に簡単な解決策を実行しました。
cat .gitignore | sed '/^#.*/ d' | sed '/^\s*$/ d' | sed 's/^/git rm -r /' | bash
説明:
" git clean
" (man)と(man)は、無視されたディレクトリ内で無視されたパスを処理したり表示したりすることについて混乱していました。これはGit 2.32(Q2 2021)で修正されました。git ls-files -i
つまり、受け入れられた回答の2021バージョンは次のようになります。
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
^^
Elijah Newren()によるcommit b548f0f、 commit dd55fc0、 commit aa6e1b2、 commit a97c7a8、commit 2e4e43a、commit b338e9f、commit 7fe1ffd、commit 7f9dd87(12 May 2021)を参照してください。Derrick Stolee()によるcommit 4e689d8(2021年5月12日)
を参照してください。( Junio C Hamanoによってマージされました---コミット33be431、2021年5月20日)newren
derrickstolee
gitster
ls-files
:-oまたは-cが指定されていない限り、-iでエラーが発生しますサインオフ-作成者:Elijah Newren
ls-files --ignored
(man)はまたはと一緒に使用でき--others
ます--cached
。少し戸惑い、コードを掘り下げた後、それは壊れていて何も印刷されていないと思いました。追跡された無視を見つけるために使用できること
ls-files -i
にようやく気付いたとき、提出する準備ができた素敵なパッチがありました。-i
--cached
それは私の側の間違いであり、ドキュメントを注意深く読むことでこれをより明確にすることができたかもしれませんが、これは他の人も同様に犯す可能性のあるエラーだと思います。
実際、私たちのテストスイートでの2つの使用のうち、2つのうちの1つがこのエラーを引き起こしたと思います。
t1306.13では、追跡されたファイルはありません。したがって、そのテストおよび以前のテストで構築および使用されたすべての除外は、追跡されていないファイルに関するものである必要があります。
しかし、彼らは空の結果を探していたので、彼らの誤ったコマンドもたまたま空の答えを与えたので、間違いは見過ごされました。
-i
ほとんどの場合、で使用されます。これは、またはのいずれかがない場合に暗示すること-o
ができることを示唆しますが、それは後方互換性のないブレークになります。代わりに、またはエラーなしでフラグを立て、関連する2つのテストケースを更新してその意図を指定し ましょう。-i
-o
-o
-c
-i
-o
-c
つまり、がない-c
と、次のようになります(Git 2.32、2021年第2四半期以降)。
fatal: ls-files -i must be used with either -o or -c
注:これはまだ進行中の作業です。Git2.32 -rc2で元に戻されましたが、 Junio C Hamano()によるcommit 2c9f1bf、commit 1df046b(2021年5月27日)で修正されました。Elijah Newren()によるcommit 906fc55(2021年5月27日)
を参照してください。Derrick Stolee()によるcommit eef8148(2021年5月27日)
を参照してください。( Junio C Hamanoによってマージされました---コミット329d63e 、2021年5月28日)gitster
newren
derrickstolee
gitster
dir
readdir_skip_dot_and_dotdot()
:ヘルパーを紹介するサインオフ-作成者:Elijah Newren
.gitignore
本当にdファイルの履歴を整理したい場合は、最初.gitignore
にリポジトリの外に保存します。たとえば、として保存して/tmp/.gitignore
から、を実行します。
git filter-branch --force --index-filter \
"git ls-files -i -X /tmp/.gitignore | xargs -r git rm --cached --ignore-unmatch -rf" \
--prune-empty --tag-name-filter cat -- --all
ノート:
git filter-branch --index-filter
私が思うディレクトリで実行され.git
ます。つまり、相対パスを使用する場合は、最初にもう1つ追加する必要があります../
。そして、どうやら../.gitignore
、実際の.gitignore
ファイルを使用することはできません。これは、何らかの理由で「致命的:../.gitignoreを除外ファイルとして使用できません」を生成します(おそらくgit filter-branch --index-filter
、作業ディレクトリが空であると見なされますか?)git ls-files -iX <(git show $(git hash-object -w .gitignore))
他の場所へのコピーを避けるために、代わりにのようなものを使用したいと思っていまし.gitignore
たが、それだけですでに空の文字列が返されるため(cat <(git show $(git hash-object -w .gitignore))
実際には.gitignore
、期待どおりにの内容が出力されます)、で使用することはできませ<(git show $GITIGNORE_HASH)
んgit filter-branch
....gitignore
特定のブランチのみをクリーンアップする場合--all
は、最後の行をその名前に置き換えます。その--tag-name-filter cat
場合、は正しく機能しない可能性があります。つまり、単一のブランチのタグを直接正しく転送できない可能性があります。Linuxでは、次のコマンドを使用できます。
たとえば、削除したい*.py~
ので、コマンドは==>になります。
find . -name "*.py~" -exec rm -f {} \;
このソリューションは、キャリッジリターン(私はWSLユーザーなので、これは重要です)と括弧のエスケープ(LaTeXユーザーにとって重要な場合があります)を追加します*.synctex(busy)
。
スコットのソリューションに触発されました:
cat .gitignore | sed "s/\r//" | sed -r "/^(#.*|\s*)$/d" | sed -r "s/([()])/\\\\\1/g" | sed "s/^/git rm -r /" | bash
s/\r//
)。/^#.*$/
)、空の行グループ(/^\s*$/
、空白または空の行に一致)を含む行を削除します。パイプ|
文字に注意してください。これは標準の正規表現であり、必要です-r
(ただし、これも機能すると思います-E
)。/([()])/
をエスケープされたバージョン\\\1
で\1
、グループと一致します。この場合、一致したものはすべて、、または、を意味[()]
し(
ます)
。フラグに注意してください。これは、すべての括弧g
に一致(および置換)するためのものです。あなたがそれに興味があるかのように書き直すことができます。"s/(\(|\))/\\\\\1/g"
git rm -r
交換はのように見えますs/$old/$new/$flags
。削除はのように見えます/$old/d
。プリペンディングは置き換えて/^/
います。そして、を置き換えることで追加を行うことができます/$/
。そしてもちろん、私が知る限り、bashで生の文字列を作成できないため、一部の文字はエスケープされます。最後に、この行は要約できますが、読みやすくするために拡張したままにすることにしました。
私は誰かが(スコットの解決策で)sed
簡単な質問をしているのを見ました。私はこの方法を最も基本的で最も猿のように考えるのが好きです。これは良い方法です。これのバリエーションが必要になった場合は、その場で作成できるからです。そして、どちらかといえば、正規表現を練習することは良い言い訳です。
gitは、.gitignoreに追加した後、.gitignoreパターンに一致するファイルを無視します。
ただし、リポジトリにすでに存在するファイルは引き続き存在します。
git rm files_ignored; git commit -m 'rm no use files'
無視されたファイルを削除するために使用します。