web-dev-qa-db-ja.com

追跡されたが現在.gitignoreにあるファイルについてGitに「忘れさせる」にはどうすればいいですか?

gitによって追跡されていたファイルがありますが、現在そのファイルは.gitignoreリストにあります。

しかし、そのファイルは編集後もgit statusに表示され続けます。どうしてgitにそれを完全に忘れるように強制するのですか?

4393
Ivan

.gitignoreは、追跡されていないファイルが(add -fを付けずに)gitによって追跡されているファイルのセットに追加されるのを防ぎます。

ファイルの追跡を停止するには、インデックスからファイルを削除する必要があります。これはこのコマンドで実現できます。

git rm --cached <file>

最新リビジョンからのファイルの削除は次のコミットで起こります。

警告:これはあなたのローカルから物理ファイルを削除しませんが、それは次のgit pullに他の開発者のマシンからファイルを削除します。 

4420
CB Bailey

以下の一連のコマンドはGitインデックスから(作業ディレクトリやローカルリポジトリからではなく)すべての項目を削除し、Gitが無視することを考慮しながらGitインデックスを更新します。 PS。インデックス=キャッシュ

最初:

git rm -r --cached . 
git add .

そして:

git commit -am "Remove ignored files"
2233
Matt Frear

git update-index 私に代わって仕事をします。

git update-index --assume-unchanged <file>

注: gitignoreは追跡されていないファイルのみを対象としているため、この解決策は実際には.gitignoreから独立しています。

edit: この回答が投稿されてから、新しいオプションが作成されました。それを推奨します。--skip-worktreeを使用してください。これはユーザーがもうコミットしたくない変更追跡ファイル用であり、gitが大きな追跡ファイルの状況をチェックするのを防ぐために--assume-unchangedをパフォーマンス用に維持するためです。詳しくは https://stackoverflow.com/a/13631525/717372 を参照してください... 

git update-index --skip-worktree <file>
861
Konstantin
git ls-files --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

これは無視されたファイルのリストを取り、それらをインデックスから削除し、そして変更をコミットします。

241
thSoft

私はいつもこのコマンドを使って、追跡されていないファイルを削除します。 1行のUnixスタイルのきれいな出力

git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

無視されたすべてのファイルを一覧表示し、スペースを含むパスを処理する代わりにすべての出力行を引用符で囲み、インデックスからパス/ファイル/ディレクトリを削除するためにすべてをgit rm -r --cachedに渡します。

64
David Hernandez

他の人が必要としているために追跡ファイルをgit rmできない場合( you git rm --cachedであっても警告、他の誰かがこの変更を受けると、それらのファイルはファイルシステムから削除されます)これらは設定ファイルの上書き、認証資格情報などが原因でよく行われます。問題を回避する方法については https://Gist.github.com/1423106 をご覧ください。

要約する:

  • アプリケーションで無視されたファイルconfig-overide.iniを探し、それをコミットされたファイルconfig.ini上で使用するようにします(または代わりに〜/ .config/myapp.ini、または$ MYCONFIGFILEを探します)。
  • ファイルconfig-sample.iniをコミットし、ファイルconfig.iniを無視するか、必要に応じてスクリプトなどを使用して必要に応じてファイルをコピーします。
  • Gitattributes clean/smudge magicを使用して変更を適用および削除します。たとえば、設定ファイルを別のブランチからのチェックアウトとして汚れさせ、設定ファイルをHEADからのチェックアウトとして消去します。これはトリッキーなことです、私は初心者ユーザーにはお勧めしません。
  • 設定ファイルは、masterにマージされることのない専用のdeployブランチに置いてください。デプロイ/コンパイル/テストしたいときは、そのブランチにマージしてそのファイルを入手してください。これは、人のマージポリシーとextra-gitモジュールを使用することを除いて、本質的に汚れ/クリーンなアプローチです。
  • アンチリメンテーション:assume-changedを使用しないでください。涙が出るだけです(gitをそれ自体に当てると、変更が永久に失われるなど、悪いことが起こる可能性があります)。
53
Seth Robertson

それを外に出し、コミットしてから元に戻すこれを達成するには、おそらく「もっと上手な」方法があるでしょう。

50
Joel Hooks

ときにこれを使用します。

1.たくさんのファイルをアントラックしたい、または

2.あなたのgitignoreファイルを更新しました

ソースリンク: http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/ /

あなたがすでにあなたのgitリポジトリにいくつかのファイルを追加/コミットし、それからそれらをあなたの.gitignoreに追加したとしましょう。これらのファイルはまだリポジトリインデックスに存在します。この記事では、それらを取り除く方法を説明します。

ステップ1:すべての変更を確定する

先に進む前に、.gitignoreファイルを含め、すべての変更がコミットされていることを確認してください。

ステップ2:リポジトリからすべてを削除する

レポをクリアするには、次のようにします。

git rm -r --cached .
  • rm はremoveコマンドです
  • -r は再帰的な削除を許可します
  • –cached はインデックスからファイルを削除するだけです。あなたのファイルはまだそこにあります。

rmコマンドは寛容でない場合があります。事前に試してみたい場合は、-nまたは--dry-runフラグを付けてテストしてください。

ステップ3:すべてを再追加する

git add .

ステップ4:コミット

git commit -m ".gitignore fix"

あなたのリポジトリはきれいです:)

変更があなたのリモコンにも適用され、変更がそこでも有効であることを確認します。

44
Dheeraj Bhaskar

うまくいかなかったこと

(Linuxの場合)、ここでの投稿を使用してls-files --ignored --exclude-standard | xargs git rm -r --cachedアプローチを提案しました。ただし、削除されるファイル(の一部)の名前には改行/ LF/\nが埋め込まれていました。どちらの解決策も:

git ls-files --ignored --exclude-standard | xargs -d"\n" git rm --cached
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

この状況に対処します(見つからないファイルに関するエラーを受け取ります)。

それで私は申し出ます

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached

これは、 ls-files への-z引数、および xargs への-0引数を使用して、ファイル名の "厄介な"文字を安全に/正しく処理することができます。

マニュアルページ git-ls-files(1) には、次のように記載されています。

-zオプションを使用しない場合、パス名のTAB、LF、およびバックスラッシュ文字は、それぞれ\ t、\ n、および\\として表されます。

そのため、ファイル名にこれらの文字が含まれている場合、私の解決策が必要だと思います。

編集:私はそれを追加するように頼まれました---他のgit rmコマンドのように---これは削除を恒久的にするために commit が続かなければなりません。 git commit -am "Remove ignored files"

38
JonBrave

git filter-branch を使ってこれを実現しました。私が使用した正確なコマンドはmanページから取られました:

_ warning _ :これはあなたの全履歴からファイルを削除します

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD

このコマンドはコミット履歴全体を再作成し、各コミットの前にgit rmを実行し、指定されたファイルを取り除きます。コマンドを実行する前に必ずバックアップしてください。{willは失われます。

36
drrlvn
  1. .gitignoreファイルを更新します - たとえば、追跡したくないフォルダを.gitignoreに追加します。

  2. git rm -r --cached . - 必要なものと不要なものを含むすべての追跡ファイルを削除します。ローカルに保存している限り、あなたのコードは安全です。

  3. git add . - .gitignore内のファイルを除いて、すべてのファイルが再度追加されます。


私たちを正しい方向に向けるために@AkiraYamamotoへのハットチップ。

18
Chen_Wayne

私は、そのgitはその概念のためにファイルについて完全に忘れることができないと思います( 「スナップショット、違いはありません」 )。

たとえば、CVSを使用している場合は、この問題はありません。 CVSは情報をファイルベースの変更のリストとして保存します。 CVSのための情報はファイルのセットと時間の経過と共に各ファイルに加えられた変更です。

しかしGitでは、プロジェクトをコミットしたり、プロジェクトの状態を保存したりするたびに、基本的にその時点でのすべてのファイルの様子を描き、そのスナップショットへの参照を保存します。 。そのため、一度ファイルを追加した場合、そのスナップショットには常に存在します。

この2記事は私にとって役に立ちました:

git想定変更なし/ skip-worktree and Gitで追跡ファイルの変更を無視する方法

それに基づいて、ファイルが既に追跡されている場合、私は次のことを行います。

git update-index --skip-worktree <file>

これ以降、このファイル内のローカルの変更はすべて無視され、リモートには反映されません。ファイルがリモートで変更された場合、git pullのときに競合が発生します。 Stashは機能しません。これを解決するには、安全な場所にファイルの内容をコピーしてくださいそして次の手順に従ってください。

git update-index --no-skip-worktree <file>
git stash
git pull 

ファイルの内容はリモートの内容に置き換えられます。変更を安全な場所からファイルに貼り付けて再度実行します。

git update-index --skip-worktree <file>

プロジェクトを扱うすべての人がgit update-index --skip-worktree <file>を実行するのであれば、pullに関する問題はなくなるはずです。すべての開発者が独自のプロジェクト構成を持っている場合、この解決策は構成ファイルには問題ありません。

ファイルがリモートで変更されたときに毎回これを実行することはあまり便利ではありませんが、リモートコンテンツによる上書きからファイルを保護することはできます。

13
Boolean_Type

次の手順を順番に実行してください、大丈夫です。

1.誤って追加されたファイル をディレクトリ/ storage から削除します。 "rm -r"(Linux用)コマンドを使用するか、ディレクトリを参照してそれらを削除できます。または、それらをあなたのPC上の別の場所に移動させてください[ moving /取り外し ]の場合はIDEを閉じる必要があります。

2.ファイル/ディレクトリをgitignoreファイルに追加して保存します。

3.now remove それらを git cacheから これらのコマンドを使用して(複数のディレクトリがある場合は、このコマンドを繰り返し発行してそれらを順次削除する)

git rm -r --cached path-to-those-files

4.now do a commitおよびPush これらのコマンドを使用します。これは これらのファイルをgit remote から削除し、git トラッキングを停止する とする。

git add .
git commit -m "removed unnecessary files from git"
git Push Origin

コピー/貼り付けの答えはgit rm --cached -r .; git add .; git statusです

このコマンドはすでにGitリポジトリにコミットされているファイルを無視しますが、それらを.gitignoreに追加しました。

5
youhans

Matt Fearからの回答が最も効果的な私見でした。以下は、Windowsのユーザーが除外リストに一致するファイルをgitリポジトリから削除するためのPowerShellスクリプトです。

# Get files matching exclusionsfrom .gitignore
# Excluding comments and empty lines
$ignoreFiles =  gc .gitignore | ?{$_ -notmatch  "#"} |  ?{$_ -match  "\S"} | % {
                    $ignore = "*" + $_ + "*"
                    (gci -r -i $ignore).FullName
                }
$ignoreFiles = $ignoreFiles| ?{$_ -match  "\S"}

# Remove each of these file from Git 
$ignoreFiles | % { git rm $_}

git add .
5
Ameer Deen

ファイルを安全な場所に移動またはコピーして、紛失しないようにします。それからファイルをgit rmしてコミットします。以前のコミットのいずれか、または削除されていない別のブランチに戻ってもファイルは表示されます。ただし、今後のコミットでは、ファイルは二度と表示されなくなります。ファイルがgit ignore内にある場合は、そのファイルをフォルダに戻すと、gitはそれを認識しません。

5
Apreche

BFG は、Gitリポジトリから大きなファイルやパスワードなどの不要なデータを削除するために特別に設計されているので、大きな履歴(現在のコミットではない)ファイルを削除する単純なフラグがあります。 : '--strip-blobs-bigger-than'

$ Java -jar bfg.jar --strip-blobs-bigger-than 100M

ファイルを名前で指定したい場合は、それもできます。

$ Java -jar bfg.jar --delete-files *.mp4

BFGはgit filter-branchよりも10〜1000倍速く、一般的にずっと使いやすくなっています。詳細については 完全な使用法の説明 を参照してください。

出典: https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html

3
Meir Gerenstadt

CLIを使用したくなく、Windowsで作業している場合、非常に簡単な解決策は TortoiseGit を使用することです。

2
Pedi T.

私はJonBraveの答えを気に入っていましたが、commit -aが私を少し怖がらせるための十分な作業ディレクトリが混乱しています。

git config - グローバルエイリアス.exclude-ignored '!git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r - キャッシュ&git ls-files -z --ignored --exclude-standard | xargs -0 git stage && git stage .gitignore && git commit -m "新しいgitignoreと無視されたファイルのインデックスからの削除" '

それを分解する:

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached 
git ls-files -z --ignored --exclude-standard | xargs -0 git stage 
git stage .gitignore 
git commit -m "new gitignore and remove ignored files from index"
  • 無視されたファイルをインデックスから削除する
  • ステージ.gitignoreと削除したばかりのファイル
  • コミット
2
Jay Irvine

これは最新のgitでは問題になっていません (執筆時点のv2.17.1).

.gitignoreはついに追跡されたが削除されたファイルを無視します。次のスクリプトを実行して、これを自分でテストすることができます。最後のgit statusステートメントは、「コミットするものがない」と報告します。

# Create empty repo
mkdir gitignore-test
cd gitignore-test
git init

# Create a file and commit it
echo "hello" > file
git add file
git commit -m initial

# Add the file to gitignore and commit
echo "file" > .gitignore
git add .gitignore
git commit -m gitignore

# Remove the file and commit
git rm file
git commit -m "removed file"

# Reintroduce the file and check status.
# .gitignore is now respected - status reports "nothing to commit".
echo "hello" > file
git status
1
Lloyd

特にIDEベースのファイルのために、私はこれを使います:

例えばslnx.sqlite、私はちょうどそれを以下のように完全に取り除きました:

git rm {PATH_OF_THE_FILE}/slnx.sqlite -f
git commit -m "remove slnx.sqlite"

これらのファイルの中には、プロジェクトのローカルユーザー設定や設定(開いているファイルなど)が保存されているものもあります。そのため、IDEをナビゲートまたは変更するたびにそのファイルは変更されるため、チェックアウトされてコミットされていない変更があることが示されます。

1
curiousBoy

git rm --cachedコマンドを使用しても元の質問には答えません。

どうやってgitに[ファイル]を完全に忘れるように強制するのですか?

実際、この解決法はgit pull!を実行すると、リポジトリの他のすべてのインスタンスでファイルを deleted にします。

Gitにファイルについて忘れるように強制する正しい方法はGitHub here で文書化されています。

ドキュメントを読むことをお勧めしますが、基本的には:

git fetch --all
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch full/path/to/file' --Prune-empty --tag-name-filter cat -- --all
git Push Origin --force --all
git Push Origin --force --tags
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --Prune=now

full/path/to/fileをファイルのフルパスに置き換えてください。ファイルを.gitignoreに追加したことを確認してください。

また、(一時的に) あなたのリポジトリへの早送りでないプッシュを許可する必要があります あなたのgit履歴を変更しているので.

1
Skeets

DS_Storeが既にコミットされている場合:

find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch

無視してください。

echo ".DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global

最後に、コミットしましょう。

0
user7718859

このメソッドは、gitを完全に忘れます無視されたファイル(past/ present/future )、ただし、notは作業ディレクトリから何も削除しません(リモートから再プルされた場合でも)。

この方法では、/.git/info/exclude(推奨)またはapre-existing.gitignore inall無視/忘れられるファイルがあるコミット。 1

Gitを強制するすべての方法は、事後の動作を事実上無視し、履歴を効果的に書き換えます。したがって、このプロセスの後にプルされる可能性のあるパブリック/共有/コラボレーションリポジトリに対して significant ramifications があります。 2

一般的なアドバイス:きれいなレポジトリで開始-コミットされたすべて、作業ディレクトリまたはインデックスで保留中のものは何もない、バックアップ

また、コメント/ リビジョン履歴 of this answerand revision history of this question )は有用/啓発的かもしれません。

#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch

git add .gitignore
git commit -m "Create .gitignore"

#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch

git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached

#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --Prune-empty flag in the following command
#this command must be run on each branch

git commit -m "ignored index"

#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits.  If deliberate "empty" commits should be kept, remove --Prune-empty and instead run git reset HEAD^ immediately after this command

git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --Prune-empty --tag-name-filter cat -- --all

#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch

git ls-files --other --ignored --exclude-standard

最後に、残りの this GitHubガイド (手順6以降)に従います。これには、以下のコマンドに関する重要な警告/情報が含まれます

git Push Origin --force --all
git Push Origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --Prune=now

変更されたリモートリポジトリからプルする他の開発者は、バックアップを作成してから、次の操作を行う必要があります。

#fetch modified remote

git fetch --all

#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed
#Switching branches after this procedure WILL LOOSE all newly-gitignored files in working directory because they are no longer tracked when switching branches

git reset FETCH_HEAD

脚注

1 /.git/info/excludeは上記の手順を使用してすべての履歴コミットに適用できるため、おそらく.gitignoreファイル into を必要とする履歴コミットの取得に関する詳細この答えの範囲を超えています。ルートコミットに適切な.gitignoreが必要でした。あたかもそれが最初にしたように。 /.git/info/excludeがコミット履歴のどこに存在するかに関係なく.gitignoreが同じことを達成でき、明確に履歴を書き換えることはveryramifications を認識している場合でも、微妙な件名。

FWIW、潜在的なメソッドには、 への回答のように、 external git rebaseを各コミットにコピーするgit filter-branchまたは.gitignoreが含まれる場合がありますこの質問

2 スタンドアロンのgit rm --cachedコマンドの結果をコミットすることによりgit ignore behaviorを強制すると、将来的にファイルが無視される可能性がありますdeletion力で押したリモコンから引っ張ります。次の--Prune-emptyコマンドのgit filter-branchフラグは、以前の「すべての無視されたファイルを削除」インデックスのみのコミットを自動的に削除することにより、この問題を回避します。 git履歴を書き換えると、コミットハッシュも変更されます。これは、public/shared/collaborativeリポジトリからの将来のプルで wreak havoc になります。そのようなレポに対してこれを行う前に、 ramifications を完全に理解してください。 このGitHubガイド は以下を指定します。

共同編集者に、 rebase not merge、古い(汚染された)リポジトリ履歴から作成したブランチを伝えます。 1回のマージコミットで、パージの問題に陥った汚染された履歴の一部またはすべてを再導入できます。

リモートリポジトリに影響しない代替ソリューションは、git update-index --assume-unchanged </path/file>またはgit update-index --skip-worktree <file>で、その例は にありますhere

0
goofology