Git: Wie entferne ich eine Datei aus dem historischen Commit?

113

Ich habe ein Commit mit der ID 56f06019 (zum Beispiel). Bei diesem Commit habe ich versehentlich eine große Datei (50 MB) festgeschrieben. In einem anderen Commit füge ich die gleiche Datei hinzu, aber in der richtigen Größe (klein). Jetzt ist mein Repo beim Klonen zu schwer :( Wie entferne ich diese große Datei aus dem Repo-Verlauf, um die Größe meines Repos zu verringern?

Marioosh
quelle
In meinem Fall handelt es sich nicht um eine große Datei, sondern um eine Konfigurationsdatei mit Datenbank-Credits. Ich habe Git studiert, damals wusste ich nichts von Gitignore.
Raschi
1
verwandte help.github.com/articles/…
Trevor Boyd Smith

Antworten:

165

Kapitel 9 des Pro Git- Buches enthält einen Abschnitt zum Entfernen von Objekten .

Lassen Sie mich hier kurz die Schritte skizzieren:

git filter-branch --index-filter \
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \
    --tag-name-filter cat -- --all

Wie bei der zuvor beschriebenen Neubasierungsoption filter-branchhandelt es sich um einen Umschreibvorgang. Wenn Sie den Verlauf veröffentlicht haben, müssen Sie --forcedie neuen Refs verschieben.

Der filter-branchAnsatz ist wesentlich leistungsfähiger als der rebaseAnsatz, da er

  • ermöglicht es Ihnen, an allen Zweigen / Refs gleichzeitig zu arbeiten,
  • benennt alle Tags im laufenden Betrieb um
  • funktioniert einwandfrei, auch wenn seit dem Hinzufügen der Datei mehrere Zusammenführungs-Commits aufgetreten sind
  • funktioniert auch dann einwandfrei, wenn die Datei im Verlauf von (a) Zweig (en) mehrmals (neu) hinzugefügt / entfernt wurde.
  • erstellt keine neuen, nicht verwandten Commits, sondern kopiert sie, während die ihnen zugeordneten Bäume geändert werden. Dies bedeutet, dass Dinge wie signierte Commits, Commit-Notizen usw. erhalten bleiben

filter-branch Bewahrt auch Backups auf, sodass die Größe des Repos nicht sofort abnimmt, es sei denn, Sie verfallen die Reflogs und die Müllabfuhr:

rm -Rf .git/refs/original       # careful
git gc --aggressive --prune=now # danger
sehe sehen
quelle
1
Es ist erwähnenswert, dass dies unter Windows cmd.exe nicht zu funktionieren scheint. Scheint aber unter Cygwin gut zu funktionieren.
Gefälschter Name
2
Ich habe den obigen Git-Filter-Zweig zum
Laufen
1
Was für mich funktioniert hat, war diese Filter-Verzweigungs-Befehlszeile. git filter-branch --force --index-filter 'git rm --ignore-unmatch --cached PathTo/MyFile/ToRemove.dll' -- fbf28b005^.. Dann rm --recursive --force .git/refs/originalund rm --recursive --force .git/logs dann habe ich das git prune --expire now und git gc --aggressive Dies hat für mich besser funktioniert als Ihre genauen Schritte oben aufgeführt. Vielen Dank, dass Sie den Link zum Git Pro-Buch aufgenommen haben, da es von unschätzbarem Wert war.
dacke.geo
Nach dem Befehl filter-branch konnte ich die Größe des .git-Ordners nur verringern, indem ich dem hier angegebenen Befehl folgte: stackoverflow.com/questions/1904860/… git -c gc.reflogExpire = 0 -c gc. reflogExpireUnreachable = 0 -c gc.rerereresolved = 0 \ -c gc.rerereunresolved = 0 -c gc.pruneExpire = jetzt gc "$ @"
Steve Ardis
Zum Verkleinern des Repos habe ich die Befehle verwendet, die in git filter-branch doc aufgeführt sind: git-scm.com/docs/…
Ludovic Ronsin
0

Sie müssen git rebase im interaktiven Modus ausführen. Ein Beispiel finden Sie hier: Wie kann ich ein Commit auf GitHub entfernen? und wie man alte Commits entfernt .

Wenn Ihr Commit bei HEAD minus 10 Commits liegt:

$ git rebase -i HEAD~10

Nach der Ausgabe Ihres Verlaufs müssen Sie den "neuen" Verlauf pushen, Sie müssen den +to force hinzufügen (siehe die Referenz in den Push-Optionen ):

$ git push origin +master

Wenn andere Personen Ihr Repository bereits geklont haben, werden Sie sie informieren, da Sie gerade den Verlauf geändert haben.

Loïc d'Anterroches
quelle
3
Das macht nicht die große Datei aus der Geschichte entfernen. Auch die kanonische Art, Push zu erzwingen, ist git push --forceoder git push -f(was nicht erfordert, dass die Leute das Zweig-Push-Ziel kennen)
sehe
Basierend auf der Frage ist die neue Datei genau die gleiche wie die alte Datei, dh der gleiche Pfad. Aus diesem Grund können Sie git rmden Pfad nicht direkt verwenden .
Loïc d'Anterroches
2
@sehe, wenn Sie eine Rebase durchführen, um das Commit mit der riesigen Datei zu eliminieren, ist es endgültig weg.
vonbrand
@vonbrand nur von dem Zweig, den Sie neu basiert haben. Ich gehe nicht davon aus, dass der Zweig 'Von' gelöscht wird. Aber ja, wenn Sie einen Revisionsbaumzweig löschen, hilft das: _
sehe
@sehe, klar, du musst alle Zweige jagen, die das beleidigende Commit enthalten. Wenn es vor etwas Buschigkeit im Repo ist, müssen Sie viel neu organisieren. Aber Rebase ist das Werkzeug dafür.
vonbrand
0

Ich habe versucht, die folgende Antwort unter Windows https://stackoverflow.com/a/8741530/8461756 zu verwenden

Einfache Anführungszeichen funktionieren unter Windows nicht. Sie benötigen doppelte Anführungszeichen.

Das Folgende hat bei mir funktioniert.

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PathRelativeRepositoryRoot / bigfile.csv" - --all

Nachdem ich die große Datei entfernt hatte, konnte ich meine Änderungen an Github Master übertragen.

Sandeep Dixit
quelle
0

Sie können einen einfachen Befehl zum Löschen verwenden

 git rm -r -f app/unused.txt 
 git rm -r -f yourfilepath
Mini-Entwickler
quelle