682 Stimmen

Wie entfernt man Dateien, die in .gitignore aufgeführt sind, aber noch im Repository vorhanden sind?

Ich habe einige Dateien in meinem Repository, die ignoriert werden sollten, ich habe sie zu .gitignore hinzugefügt, aber natürlich werden sie nicht aus meinem Repository entfernt.

Meine Frage ist also, ob es einen magischen Befehl oder ein Skript gibt, das mit filter-branch meinen Verlauf umschreibt und alle diese Dateien einfach entfernt? Oder einfach einen Befehl, der einen Commit erstellt, der sie entfernt?

4voto

VonC Punkte 1117238

" git clean " ( man ) y git ls-files -i ( man ) gab es Verwirrung bei der Arbeit an oder der Anzeige von ignorierten Pfaden innerhalb eines ignorierten Verzeichnisses, was mit Git 2.32 (Q2 2021) behoben wurde.

Das bedeutet, dass die Version 2021 von die akzeptierte Antwort wäre:

git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached  
                ^^

Siehe Übergabe b548f0f , dd55fc0 übertragen , aa6e1b2 übergeben , a97c7a8 übergeben , festlegen 2e4e43a , Übergabe b338e9f , 7fe1ffd übertragen , 7f9dd87 übertragen (12. Mai 2021) von Elijah Newren ( newren ) .
Siehe Übergabe 4e689d8 (12. Mai 2021) von Derrick Stolee ( derrickstolee ) .
(Zusammengefasst von Junio C. Hamano -- gitster -- en 33be431 festlegen , 20. Mai 2021)

ls-files Fehler bei -i, wenn nicht -o oder -c angegeben sind

Abgezeichnet von: Elijah Newren

ls-files --ignored ( man ) kann entweder zusammen mit --others o --cached .

Nachdem ich ein wenig ratlos war und mich in den Code vertieft hatte, nahm ich an, dass ls-files -i war einfach kaputt und hat nichts gedruckt, und ich hatte einen schönen Patch fertig, als ich endlich merkte, dass -i kann verwendet werden mit --cached um verfolgte Ignoranten zu finden.

Das war zwar ein Fehler meinerseits, und ein sorgfältiges Lesen der Dokumentation hätte dies deutlicher machen können, aber ich vermute, dass dieser Fehler auch anderen unterlaufen kann.
Von zwei Anwendungen in unserer Testsuite hat einer der beiden diesen Fehler gemacht.
In t1306.13 gibt es KEINE verfolgten Dateien, und alle Ausschlüsse, die in diesem Test und in früheren Tests erstellt und verwendet wurden, müssen sich daher auf nicht verfolgte Dateien beziehen.
Da sie jedoch nach einem leeren Ergebnis suchten, blieb der Fehler unbemerkt, da ihr fehlerhafter Befehl zufällig auch eine leere Antwort ergab.

-i wird in den meisten Fällen verwendet mit -o was bedeuten würde, dass wir einfach -i implizieren -o in Ermangelung eines -o o -c aber das wäre ein rückwärtsinkompatibler Bruch.
Stattdessen markieren wir einfach -i entweder ohne eine -o o -c als Fehler zu bezeichnen und die beiden relevanten Testfälle zu aktualisieren, um ihre Absicht zu spezifizieren.

Das heißt, ohne -c erhalten Sie (ab Git 2.32, Q2 2021):

fatal: ls-files -i must be used with either -o or -c

Hinweis: Dies ist ein noch nicht abgeschlossenes Projekt, da es rückgängig gemacht in Git 2.32-rc2 aber fixiert mit 2c9f1bf übertragen , Commit 1df046b (27. Mai 2021) von Junio C. Hamano ( gitster ) .
Siehe 906fc55 übertragen (27. Mai 2021) von Elijah Newren ( newren ) .
Siehe eef8148 festlegen (27. Mai 2021) von Derrick Stolee ( derrickstolee ) .
(Zusammengefasst von Junio C. Hamano -- gitster -- en 329d63e übergeben , 28. Mai 2021)

dir : einführen readdir_skip_dot_and_dotdot() Hilfskraft

Abgezeichnet von: Elijah Newren

2voto

Jaacko Torus Punkte 498

Diese Lösung fügt Zeilenumbrüche hinzu (ich bin WSL-Benutzer, daher ist das wichtig) und Klammerausbrüche (was für LaTeX-Benutzer manchmal wichtig ist, z. B. *.synctex(busy) ).


Inspiriert durch Scotts Lösung :

cat .gitignore | sed "s/\r//" | sed -r "/^(#.*|\s*)$/d" | sed -r "s/([()])/\\\\\1/g" | sed "s/^/git rm -r /" | bash
  1. Entfernen: Wagenrücklauf ( s/\r// ).
  2. Zeilen entfernen, die Folgendes enthalten: Kommentare ( /^#.*$/ ), leere Zeilengruppen ( /^\s*$/ , entspricht Leerzeichen oder Leerzeile). Beachten Sie die Pipe | Zeichen, dies ist ein Standard-Regex, und erfordert -r (obwohl ich glaube, dass -E funktioniert auch).
  3. Ersetzen: Klammerung /([()])/ mit seiner escapeten Version \\\1 , \1 mit der Gruppe übereinstimmt, bedeutet das in diesem Fall [()] , oder ( o ) was auch immer abgestimmt wurde. Beachten Sie die g Flagge, dies soll übereinstimmen (und ersetzen) alle Klammer auf. Könnte umgeschrieben werden als "s/(\(|\))/\\\\\1/g" wenn Sie darauf stehen.
  4. vorangestellt. git rm -r

Die Ersetzung sieht wie folgt aus s/$old/$new/$flags . Die Entfernung sieht folgendermaßen aus /$old/d . Vorangestellt wird das Ersetzen von /^/ . Und Sie könnten das Anhängen durch Ersetzen von /$/ . Und natürlich werden einige Zeichen escaped, da man in der Bash keine rohen Zeichenketten erstellen kann, soweit ich weiß. Schließlich kann diese Zeile gekürzt werden, aber ich habe sie aus Gründen der Lesbarkeit erweitert gelassen.


Ich habe gesehen, wie jemand (in Scotts Lösung) in Frage stellte, dass sed ist ganz einfach. Ich halte diese Methode für die einfachste und affenartigste Art, es zu tun. Das ist gut, denn wenn Sie jemals eine Variation davon brauchen, können Sie sie auf der Stelle machen. Und wenn überhaupt, dann ist es eine gute Ausrede, um reguläre Ausdrücke zu üben.

1voto

Tobias Kienzler Punkte 23415

Wenn Sie Ihre Geschichte wirklich bereinigen wollen .gitignore d-Dateien, speichern Sie zuerst .gitignore außerhalb des Repo, z.B. als /tmp/.gitignore und führen Sie dann

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

Anmerkungen:

  • git filter-branch --index-filter läuft im .git Verzeichnis, d.h. wenn Sie einen relativen Pfad verwenden wollen, müssen Sie einen weiteren ../ Erstens. Und offenbar können Sie nicht mit ../.gitignore die aktuelle .gitignore Datei, die aus irgendeinem Grund ein "fatal: cannot use ../.gitignore as an exclude file" ergibt (vielleicht während einer git filter-branch --index-filter das Arbeitsverzeichnis (als) leer betrachtet wird?)
  • Ich hatte gehofft, etwas zu verwenden wie git ls-files -iX <(git show $(git hash-object -w .gitignore)) stattdessen, um das Kopieren zu vermeiden .gitignore irgendwo anders, aber das allein ergibt schon einen leeren String (während cat <(git show $(git hash-object -w .gitignore)) druckt tatsächlich .gitignore Inhalt wie erwartet), daher kann ich die <(git show $GITIGNORE_HASH) en git filter-branch .
  • Wenn Sie eigentlich nur .gitignore -einen bestimmten Zweig bereinigen, ersetzen --all in der letzten Zeile mit seinem Namen. Die --tag-name-filter cat könnte dann nicht richtig funktionieren, d.h. Sie werden wahrscheinlich nicht in der Lage sein, die Tags eines einzelnen Zweigs direkt und korrekt zu übertragen

-1voto

Saloua SAHNOUNE Punkte 199

Unter Linux können Sie diesen Befehl verwenden:

Ich möchte zum Beispiel Folgendes löschen *.py~ mein Befehl sollte also lauten ==>

find . -name "*.py~" -exec rm -f {} \;

-5voto

pensz Punkte 1871

Git ignoriert die Dateien, die dem .gitignore-Muster entsprechen, nachdem Sie sie zu .gitignore hinzugefügt haben.

Aber die Dateien, die bereits im Repository vorhanden sind, bleiben erhalten.

utiliser git rm files_ignored; git commit -m 'rm no use files' um ignorierte Dateien zu löschen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X