Ich filename.orig
habe vor einigen Commits versehentlich eine unerwünschte Datei ( beim Auflösen einer Zusammenführung) in mein Repository übernommen, ohne dass ich es bisher bemerkt habe. Ich möchte die Datei vollständig aus dem Repository-Verlauf löschen.
Ist es möglich, den Änderungsverlauf so umzuschreiben, dass er überhaupt filename.orig
nicht zum Repository hinzugefügt wurde?
git
git-filter-branch
git-rewrite-history
git-rm
Grant Limberg
quelle
quelle
Antworten:
Bitte verwenden Sie dieses Rezept nicht, wenn Ihre Situation nicht der in der Frage beschriebenen entspricht. Dieses Rezept dient zum Beheben einer schlechten Zusammenführung und zum Wiederholen Ihrer guten Commits für eine feste Zusammenführung.
Obwohl
filter-branch
es tun wird, was Sie wollen, ist es ein ziemlich komplexer Befehl, und ich würde mich wahrscheinlich dafür entscheiden, dies zu tungit rebase
. Es ist wahrscheinlich eine persönliche Präferenz.filter-branch
Dies kann in einem einzigen, etwas komplexeren Befehl ausgeführt werden, während dierebase
Lösung die entsprechenden logischen Operationen Schritt für Schritt ausführt.Probieren Sie das folgende Rezept:
(Beachten Sie, dass Sie eigentlich keinen temporären Zweig benötigen. Sie können dies mit einem 'getrennten HEAD' tun. Sie müssen jedoch die Commit-ID notieren, die durch den
git commit --amend
Schritt generiert wurde , um dengit rebase
Befehl bereitzustellen, anstatt den temporären Zweig zu verwenden Name.)quelle
git rebase -i
schneller und trotzdem so einfach? $ git rebase -i <sh1-of-merge> Markiere das richtige als "edit" $ git rm somefile.orig $ git commit --amend $ git rebase --continue Aus irgendeinem Grund habe ich diese Datei jedoch immer noch irgendwo als letzte Mal habe ich das gemacht. Vermutlich fehlt etwas.git rebase -i
Dies ist sehr nützlich, insbesondere wenn Sie mehrere Rebase-Operationen ausführen müssen. Es ist jedoch richtig, genau zu beschreiben, wenn Sie nicht tatsächlich über die Schulter einer Person zeigen und sehen können, was diese mit ihrem Editor tut. Ich benutze vim, aber nicht jeder würde sich freuen mit: "ggjcesquash <Esc> jddjp: wq" und Anweisungen wie "Verschiebe die oberste Zeile nach der aktuellen zweiten Zeile und ändere das erste Wort in Zeile vier in" Bearbeiten ", speichere jetzt und quit "scheint schnell komplexer zu sein als die eigentlichen Schritte. Normalerweise haben Sie auch einige--amend
und--continue
Aktionen.Einführung: Sie haben 5 Lösungen zur Verfügung
Das Originalplakat besagt:
Es gibt viele verschiedene Möglichkeiten, den Verlauf einer Datei vollständig aus git zu entfernen:
Im Fall des Originalplakats ist die Änderung des Commits für sich genommen keine Option, da er anschließend mehrere zusätzliche Commits vorgenommen hat. Der Vollständigkeit halber werde ich jedoch auch erklären, wie dies für alle anderen zu tun ist, die es nur wollen ihre vorherige Verpflichtung zu ändern.
Beachten Sie, dass bei all diesen Lösungen der Verlauf / die Commits auf eine andere Weise geändert / neu geschrieben werden müssen . Daher muss jeder Benutzer mit alten Kopien der Commits zusätzliche Arbeit leisten, um seinen Verlauf mit dem neuen Verlauf neu zu synchronisieren.
Lösung 1: Ändern von Commits
Wenn Sie in Ihrem vorherigen Commit versehentlich eine Änderung vorgenommen haben (z. B. das Hinzufügen einer Datei) und der Verlauf dieser Änderung nicht mehr vorhanden sein soll, können Sie das vorherige Commit einfach ändern, um die Datei daraus zu entfernen:
Lösung 2: Hard Reset (möglicherweise plus Rebase)
Wie bei Lösung Nr. 1 haben Sie auch die Möglichkeit, einfach einen Hard-Reset für das übergeordnete Element durchzuführen, wenn Sie nur Ihr vorheriges Commit entfernen möchten:
Dieser Befehl wird schwer zurückzusetzen Zweig zum vorherigen 1 st Eltern begehen.
Allerdings mit einem Fütterungsmaterial, wenn, wie das ursprüngliche Plakat, haben Sie mehrere Commits gemacht nach dem Commit Sie die Änderung rückgängig machen möchten, können Sie immer noch schwer Resets verwendenihn zu ändern, sondern beinhaltet auch so tun. Hier sind die Schritte, mit denen Sie ein Commit weiter hinten in der Geschichte ändern können:
Lösung 3: Nicht interaktive Wiederherstellung
Dies funktioniert, wenn Sie nur ein Commit vollständig aus dem Verlauf entfernen möchten:
Lösung 4: Interaktive Rebases
Mit dieser Lösung können Sie die gleichen Aufgaben wie mit den Lösungen Nr. 2 und Nr. 3 ausführen, dh Commits weiter hinten im Verlauf ändern oder entfernen als mit Ihrem unmittelbar vorherigen Commit. Welche Lösung Sie verwenden, liegt also ganz bei Ihnen. Interaktive Rebases sind aus Leistungsgründen nicht gut geeignet, um Hunderte von Commits neu zu gründen. Daher würde ich in solchen Situationen nicht interaktive Rebases oder die Filterzweiglösung (siehe unten) verwenden.
Verwenden Sie Folgendes, um die interaktive Rebase zu starten:
Dies führt dazu, dass git den Festschreibungsverlauf auf das übergeordnete Element des Festschreibens zurückspult, das Sie ändern oder entfernen möchten. Anschließend wird eine Liste der zurückgespulten Commits in umgekehrter Reihenfolge in dem Editor angezeigt, für den git verwendet wird (dies ist standardmäßig Vim):
Das Commit, das Sie ändern oder entfernen möchten, befindet sich oben in dieser Liste. Um es zu entfernen, löschen Sie einfach die Zeile in der Liste. Andernfalls ersetzen „Pick“ auf „Bearbeiten“ auf der 1 st Linie, etwa so:
Als nächstes geben Sie ein
git rebase --continue
. Wenn Sie das Commit vollständig entfernen möchten, ist dies alles, was Sie tun müssen (außer der Überprüfung, siehe letzter Schritt für diese Lösung). Wenn Sie andererseits das Commit ändern möchten, wendet git das Commit erneut an und pausiert dann die Rebase.Zu diesem Zeitpunkt können Sie die Datei entfernen, das Commit ändern und dann die Rebase fortsetzen:
Das ist es. Als letzten Schritt sollten Sie unabhängig davon, ob Sie das Commit geändert oder vollständig entfernt haben, immer überprüfen, ob keine anderen unerwarteten Änderungen an Ihrem Zweig vorgenommen wurden, indem Sie den Status vor dem Rebase ändern:
Lösung 5: Filtern von Zweigen
Schließlich ist diese Lösung am besten geeignet, wenn Sie alle Spuren der Existenz einer Datei vollständig aus dem Verlauf entfernen möchten und keine der anderen Lösungen der Aufgabe gerecht wird.
Dadurch werden
<file>
alle Commits entfernt, beginnend mit dem Root-Commit. Wenn Sie stattdessen nur den Festschreibungsbereich neu schreiben möchten,HEAD~5..HEAD
können Sie dies als zusätzliches Argument an übergebenfilter-branch
, wie in dieser Antwort ausgeführt :Nach Abschluss des
filter-branch
Vorgangs ist es normalerweise eine gute Idee, zu überprüfen, ob keine weiteren unerwarteten Änderungen vorliegen, indem Sie Ihren Zweig vor dem Filtervorgang vom vorherigen Status unterscheiden:Filter-Branch-Alternative: BFG Repo Cleaner
Ich habe gehört, dass das BFG Repo Cleaner- Tool schneller als ausgeführt
git filter-branch
wird. Vielleicht möchten Sie dies auch als Option überprüfen. Es wird sogar offiziell in der Filterzweigdokumentation als praktikable Alternative erwähnt:Zusätzliche Ressourcen
quelle
filter-branch
Ursache Neuberechnung von Hashes? Wenn ein Team mit einem Repo arbeitet, in dem eine große Datei gefiltert werden soll, wie tun sie dies, damit alle den gleichen Status des Repos haben?Wenn Sie seitdem nichts mehr festgeschrieben haben, nur
git rm
die Datei undgit commit --amend
.Wenn Sie haben
wird jede Änderung von
merge-point
bis durchlaufenHEAD
, filename.orig löschen und die Änderung neu schreiben. Verwenden--ignore-unmatch
bedeutet, dass der Befehl nicht fehlschlägt, wenn aus irgendeinem Grund filename.orig in einer Änderung fehlt. Dies ist der empfohlene Weg aus dem Abschnitt "Beispiele" in der Manpage "git-filter-branch" .Hinweis für Windows-Benutzer: Der Dateipfad muss Schrägstriche verwenden
quelle
git-filter-branch
scheinen die erste zu geben.filter-branch
"
und nicht,'
da sonst ein nicht hilfreich formulierter Fehler "schlechte Revision" angezeigt wird.Dies ist der beste Weg:
http://github.com/guides/completely-remove-a-file-from-all-revisions
Stellen Sie einfach sicher, dass Sie zuerst die Kopien der Dateien sichern.
BEARBEITEN
Die Bearbeitung von Neon wurde bei der Überprüfung leider abgelehnt.
Siehe Neons Post unten, es könnte nützliche Informationen enthalten!
Zum Beispiel, um alle
*.gz
Dateien zu entfernen , die versehentlich in das Git-Repository übernommen wurden:Das hat bei mir immer noch nicht funktioniert? (Ich bin derzeit bei Git Version 1.7.6.1)
Ich weiß nicht warum, da ich nur EINEN Hauptzweig hatte. Wie auch immer, ich habe mein Git-Repo endlich wirklich aufgeräumt, indem ich es in ein neues leeres und nacktes Git-Repository geschoben habe, z
(Ja!)
Dann klone ich das in ein neues Verzeichnis und verschiebe es über den .git-Ordner in dieses. z.B
(Ja! endlich aufgeräumt!)
Nachdem Sie überprüft haben, ob alles in Ordnung ist, können Sie die Verzeichnisse
../large_dot_git
und löschen../tmpdir
(möglicherweise in ein paar Wochen oder Monaten, nur für den Fall ...).quelle
--prune-empty
den Befehl filter-branch hinzuzufügen .Das Umschreiben des Git-Verlaufs erfordert das Ändern aller betroffenen Commit-IDs. Daher muss jeder, der an dem Projekt arbeitet, seine alten Kopien des Repos löschen und einen neuen Klon erstellen, nachdem Sie den Verlauf bereinigt haben. Je mehr Leute es stören, desto mehr brauchen Sie einen guten Grund dafür - Ihre überflüssige Datei verursacht kein wirkliches Problem, aber wenn Sie nur an dem Projekt arbeiten, können Sie den Git-Verlauf auch bereinigen, wenn Sie möchten zu!
Um es so einfach wie möglich zu machen, würde ich empfehlen, den BFG Repo-Cleaner zu verwenden , eine einfachere und schnellere Alternative zu dem
git-filter-branch
speziell zum Entfernen von Dateien aus dem Git-Verlauf entwickelten. Eine Möglichkeit, die Ihnen das Leben hier erleichtert, besteht darin, dass standardmäßig alle Refs (alle Tags, Zweige usw.) verarbeitet werden, aber auch 10- bis 50-mal schneller.Befolgen Sie die Schritte hier sorgfältig: http://rtyley.github.com/bfg-repo-cleaner/#usage - aber das Kernbit ist genau das: Laden Sie das BFG-JAR herunter (erfordert Java 6 oder höher) und führen Sie diesen Befehl aus ::
Ihr gesamter Repository-Verlauf wird gescannt und alle benannten Dateien
filename.orig
(die nicht in Ihrem letzten Commit enthalten sind ) werden entfernt. Dies ist erheblich einfacher alsgit-filter-branch
das Gleiche zu tun!Vollständige Offenlegung: Ich bin der Autor des BFG Repo-Cleaner.
quelle
quelle
Um das zu Charles Baileys Lösung hinzuzufügen, habe ich nur eine Git-Rebase -i verwendet, um unerwünschte Dateien aus einem früheren Commit zu entfernen, und es hat wie ein Zauber funktioniert. Die Schritte:
quelle
Der einfachste Weg, den ich gefunden habe, wurde von
leontalbot
(als Kommentar) vorgeschlagen, einem von Anoopjohn veröffentlichten Beitrag . Ich denke, es ist seinen eigenen Platz wert als Antwort:(Ich habe es in ein Bash-Skript konvertiert)
Alle Credits gehen an
Annopjohn
undleontalbot
für den Hinweis.HINWEIS
Beachten Sie, dass das Skript keine Validierungen enthält. Stellen Sie daher sicher, dass Sie keine Fehler machen und dass Sie ein Backup haben, falls etwas schief geht. Es hat bei mir funktioniert, aber in Ihrer Situation funktioniert es möglicherweise nicht. BENUTZEN SIE ES MIT VORSICHT (folgen Sie dem Link, wenn Sie wissen möchten, was los ist).
quelle
Auf jeden Fall
git filter-branch
ist der Weg zu gehen.Leider reicht dies nicht aus, um es vollständig
filename.orig
aus Ihrem Repo zu entfernen , da es weiterhin von Tags, Reflog-Einträgen, Fernbedienungen usw. referenziert werden kann.Ich empfehle, auch alle diese Referenzen zu entfernen und dann den Garbage Collector aufzurufen. Sie können das
git forget-blob
Skript von dieser Website verwenden, um all dies in einem Schritt zu erledigen.git forget-blob filename.orig
quelle
Wenn es das letzte Commit ist, das Sie bereinigen möchten, habe ich es mit der Git-Version 2.14.3 (Apple Git-98) versucht:
quelle
git reflog expire --expire=now --all; git gc --prune=now
ist eine sehr schlechte Sache. Wenn Ihnen nicht der Speicherplatz ausgeht, lassen Sie Git Garbage diese Commits nach einigen Wochen sammelnDafür
git filter-branch
wurde entwickelt.quelle
Sie können auch verwenden:
git reset HEAD file/path
quelle