Die akzeptierte Antwort lässt Git nicht " eine Datei vergessen ..." (historisch). Git ignoriert die Datei nur in der Gegenwart / Zukunft.
Diese Methode lässt git ignorierte Dateien ( Vergangenheit / Gegenwart / Zukunft) vollständig vergessen , tut dies jedoch nicht löscht alles von Arbeitsverzeichnis (auch bei Wieder gezogen aus der Ferne).
Diese Methode erfordert die Verwendung von /.git/info/exclude
(bevorzugt) ODER einer bereits vorhandenen .gitignore
in allen Commits, deren Dateien ignoriert / vergessen werden müssen. 1
Alle Methoden zur Durchsetzung von Git ignorieren das Verhalten nachträglich, schreiben den Verlauf effektiv neu und haben daher erhebliche Auswirkungen auf alle öffentlichen / gemeinsam genutzten / kollaborativen Repos, die nach diesem Prozess möglicherweise abgerufen werden. 2
Allgemeiner Rat: Beginnen Sie mit einem sauberen Repo - alles festgeschrieben, nichts steht im Arbeitsverzeichnis oder Index aus, und erstellen Sie ein Backup !
Auch die Kommentare / Revisionsgeschichte von dieser Antwort ( und Revisionsgeschichte von dieser Frage ) kann nützlich sein / erleuchten.
#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
Befolgen Sie abschließend den Rest dieses GitHub-Handbuchs (ab Schritt 6), das wichtige Warnungen / Informationen zu den folgenden Befehlen enthält .
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
Andere Entwickler, die aus dem jetzt modifizierten Remote-Repo ziehen, sollten ein Backup erstellen und dann:
#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
git reset FETCH_HEAD
Fußnoten
1 Da /.git/info/exclude
mit den obigen Anweisungen auf alle historischen Commits angewendet werden kann, liegen Details zum Einfügen einer .gitignore
Datei in die historischen Commits, die sie benötigen , möglicherweise über den Rahmen dieser Antwort hinaus. Ich wollte, dass ein richtiger Mitarbeiter .gitignore
im Root-Commit ist, als wäre es das erste, was ich getan habe. Anderen ist es vielleicht egal, da /.git/info/exclude
sie das Gleiche erreichen können, unabhängig davon, wo sie .gitignore
in der Festschreibungshistorie vorhanden sind, und das klare Umschreiben der Historie ist ein sehr heikles Thema, selbst wenn sie sich der Auswirkungen bewusst sind .
FWIW können potenzielle Methoden enthalten git rebase
oder eine git filter-branch
, die ein externes .gitignore
in jedes Commit kopiert , wie die Antworten auf diese Frage
2 Das Erzwingen des nachträglichen Ignorierens von Git durch Festschreiben der Ergebnisse eines eigenständigen git rm --cached
Befehls kann dazu führen, dass neu ignorierte Dateien in zukünftigen Abrufen von der erzwungenen Fernbedienung gelöscht werden . Das --prune-empty
Flag im folgenden git filter-branch
Befehl vermeidet dieses Problem, indem das vorherige Nur-Index-Commit "Alle ignorierten Dateien löschen" automatisch entfernt wird. Durch das Umschreiben des Git-Verlaufs werden auch Commit-Hashes geändert, was bei zukünftigen Abrufen von öffentlichen / gemeinsam genutzten / kollaborativen Repos zu Chaos führen wird . Bitte verstehen Sie die Auswirkungen vollständig, bevor Sie dies für ein solches Repo tun. In diesem GitHub-Handbuch wird Folgendes angegeben:
Weisen Sie Ihre Mitarbeiter an , alle Zweige, die sie aus Ihrem alten (fehlerhaften) Repository-Verlauf erstellt haben, neu zu gründen und nicht zusammenzuführen. Ein Zusammenführungs-Commit könnte einen Teil oder die gesamte verdorbene Geschichte wieder einführen, die Sie gerade mit dem Löschen begonnen haben.
Alternative Lösungen, die das Remote-Repo nicht beeinflussen, sind git update-index --assume-unchanged </path/file>
oder git update-index --skip-worktree <file>
, Beispiele hierfür finden Sie hier .
git clean -X
klingt ähnlich, trifft aber in dieser Situation nicht zu (wenn die Dateien noch von Git verfolgt werden). Ich schreibe dies für alle, die nach einer Lösung suchen, um nicht den falschen Weg zu gehen.