2009-05-30 10 views
20

Ich habe eine 33 MB große Datei, wo ich will, um dauerhaft die ältesten Überarbeitungen dieser Datei zu löschen, so dass ich nur die neuesten X Revisionen um gehalten werden. Wie es geht?git entfernt älteste Revisionen einer Datei

Meine nackten Repository hat, weil es riesig wachsen.

Ich habe versucht, die folgend .. aber es entfernt die Datei vollständig

git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' HEAD 

Um die großen Dateien in meinem Repository ich git-large-blob by Aristotle Pagaltzis verwenden zu identifizieren.

+0

Ich denke, es würde helfen, wenn Sie mehr Informationen über diese Datei und was Sie versuchen, zu tun. Ist dies ein einmaliges Ereignis oder planen Sie, die Datei regelmäßig zu löschen und den Repository-Verlauf neu zu schreiben? Warum verfolgen Sie die Datei in git, wenn Sie ihren Verlauf nicht behalten müssen? Wie groß ist Ihr blankes Repository und ist es wirklich ein Problem, wenn es groß ist? –

+0

es ist ein Handbuch für mein Programm, ich schreibe mit Apple Pages (Textverarbeitung) und es enthält eine Menge Bilder. Ich speichere es hauptsächlich in GIT, damit ich es zwischen meinem stationären Computer und meinem Laptop teilen kann, und mache es für den Fall, dass etwas schief geht. Das Repository ist derzeit 450 MB. Ich zögere, mit der Datei zu arbeiten, weil ich weiß, dass die Repository-Größe zunimmt. Anstatt meine Backup-Lösung zu überdenken, dachte ich, dass es besser wäre, die ältesten Revisionen loszuwerden. Ich mache täglich einen vollständigen Snapshot des Repositorys und lade es hoch, aber das Festplattenkontingent beträgt 3 GB. – neoneye

+0

Ja, ich hoffe, dass es von Zeit zu Zeit möglich ist. – neoneye

Antwort

16

Ich glaube, Sie auf dem richtigen Weg sind mit dem git filter-branch Befehl Sie versuchen. Das Problem ist, dass Sie es nicht angewiesen haben, die Datei in einem Commit zu behalten, so dass sie von allen entfernt wird. Nun, ich glaube nicht, dass es eine Möglichkeit, direkt zu ist sagen git-filter-branch alle Commits zu überspringen. Da jedoch die Befehle in einem Shell-Kontext ausgeführt werden, sollte es nicht allzu schwierig sein, die Schale zu verwenden, um alle außer der letzten X Anzahl der Revisionen zu entfernen. Etwas wie folgt aus:

KEEP=10 I=0 NUM_COMMITS=$(git rev-list master | wc -l) \ 
git filter-branch --index-filter \ 
'if [[ ${I} -lt $((NUM_COMMITS - KEEP)) ]]; then 
    git rm --cached --ignore-unmatch big_manual.txt; 
fi; 
I=$((I + 1))' 

Das big_manual.txt in den letzten 10 Commits halten würde.

Das gesagt, wie Charles erwähnt hat, bin ich nicht sicher, dass dies der beste Ansatz ist, da Sie in Wirklichkeit den ganzen Punkt von VCS rückgängig machen, indem Sie alte Versionen löschen.

Haben Sie bereits versucht, das Git-Repository mit git-gc und/oder git-repack zu optimieren? Wenn nicht, könnten diese einen Versuch wert sein.

+1

das ist die Lösung! Es ging durch alle 312 Revisionen und verwarf die ältesten Revisionen, perfekt. Das war sehr lehrreich. For-Schleifen, rev-list .. und Aufruf filter-Zweig ohne irgendeine Commit-ID, die nicht intuitiv erscheint (muss untersuchen, wie diese Magie funktioniert), aber es hat funktioniert. Danke für das. Manchmal verwende ich git-gc und fsck, aber es ist noch nicht etwas, das ich automatisiert habe. Lass uns nicht über meine Meinung zu VCS sprechen :-) – neoneye

+1

>> Lass uns nicht über meine Meinung zu VCS reden :-) Fair genug :) Ich bin froh, dass das für dich funktioniert hat. Was den Zauber betrifft, keine Revision anzugeben, ruft git-filter-branch intern git-rev-list auf, um die Liste der zu schreibenden Commits zu erhalten. Es wird "HEAD" an git-rev-list als Standardreferenz übergeben, wenn Sie keine angeben. Also nichts zu spezifizieren, ist gleichbedeutend mit der Angabe von "HEAD" (wie in Ihrem Beispiel). –

+0

Danke für das Skript. Ich machte es in eine Bash-Skript-Datei und fand, dass ich es leicht anpassen musste ' #!/bin/bash KEEP = 10 I = 0 NUM_COMMITS = $ (git rev-list master | wc -l) \ git filter-filiale --index-filter \ 'if [$ {I} -lt $ ((NUM_COMMITS - HALTEN))]; dann git rm --cached --ignore-unmatch file-to-delete.tar; fi; I = $ ((I + 1)) ' ' –

15

Hinweis: diese Antwort über die Geschichte eines ganzen Projektes zu verkürzen, anstatt einzelne Datei von älterer Geschichte zu entfernen, was die Frage nach war!


Der einfachste Weg Geschichte eines gesamte Projekt zu verkürzen, indem git filter-branch Verwendung wäre verwenden Transplantate Mechanismus (siehe repository layout Dokumentation) Geschichte abzukürzen:

$ echo "$commit_id" >> .git/info/grafts 

wo $commit_id ist ein Commit, das ein Root (erstes Commit) eines neuen Repositorys sein soll. Check out „git log“ oder grafische Geschichte Betrachter wie gitk mit, dass die Geschichte sieht aus wie Sie wollen, und führen Sie „git filter-branch --all“; Die Verwendung von Transplantaten wird in der git-filter-filial-Dokumentation beschrieben.

Oder Sie können flachen Klon mit --depth <depth> Option git clone verwenden.



Sie können von Transplantate zu einem Teil der Geschichte einer einzelnen Datei entfernen Schritte (was ursprünglich angefragt) machen beschreiben mit unten. Diese Lösung besteht aus mehr Schritten als solution proposed by Dan Moulding, aber jeder der Schritte ist einfacher, und Sie können Zwischenschritte mit "git log" oder grafischem Verlaufsbetrachter überprüfen.

  1. Wählen Sie zuerst Punkt, an dem Sie Datei entfernt haben wollen, und jene Commits zu markieren, indem Zweige an den Stellen zu schaffen. Zum Beispiel, wenn Sie wollen Datei für die erste Zeit erscheinen haben in f020285b begehen und haben es in allen es Vorfahren entfernt, es Vorfahren markieren (vorausgesetzt, dies ist gewöhnlich, nicht-merge Festschreibung) über

    $ git branch cleanup f020285b^ 
    
  2. Zweitens entfernen die Datei aus der Geschichte mit cleanup beginnen (dh f020285b^) git-filter-Zweig verwendet wird, wie in Abschnitt „Beispiele“ von git-filter-branch manpage gezeigt:

    $ git filter-branch --index-filter 'git rm --cached --ignore-unmatch big_manual.txt' cleanup 
    

    Wenn Sie auch alle Commits entfernen möchten, die nur geändert hatte entfernte Datei können Sie zusätzlichverwendenOption zum Git-Filter-Zweig.

  3. Als nächstes rewritten Teil der Geschichte mit dem Rest der Geschichte mit Transplantaten Mechanismus beitreten:

    $ echo $(git-rev-parse f020285b) $(git rev-parse cleanup) >> .git/info/grafts 
    

    Dann können Sie Histry untersuchen, um zu überprüfen, ob es richtig verbunden ist.

  4. Last, macht Transplantate permanent (dies würde alle Transplantate dauerhaft machen, sondern kann hier davon ausgehen, dass Sie Transplantate nicht anderweitig verwenden) git-filter-Zweig verwenden,

    $ git filter-branch cleanup..HEAD 
    

    und Transplantationen entfernen (wie ohne dass dies, wenn Sie ein Teil der Geschichte einiger Datei entfernen, sollten Sie besser sicherstellen, dass Projekt: sie sind nicht mehr) und die cleanup Zweig

    $ rm .git/info/grafts 
    $ git branch -d cleanup 
    

Schlussbemerkung benötigt Datei macht Sinn (und kompiliert zum Beispiel richtig).

+0

interessant. werde versuchen. – neoneye

+0

Ja, der Transplantationsmechanismus scheint in der Tat der beabsichtigte Weg zu sein. Danke, dass du mich darauf aufmerksam gemacht hast. Leider habe ich heute keine Zeit, damit zu experimentieren. – neoneye

+0

Die Grafts-Methode könnte in einigen Fällen funktionieren, aber es wird die Geschichte für alle Dateien loswerden. In diesem Fall möchte neoneye nur den Verlauf für * einige * Dateien entfernen. Ich bin mir also nicht sicher, ob Transplantate eine geeignete Lösung wären. Ein oberflächlicher Klon kommt nicht in Frage, weil seichte Repositorys verkrüppelt sind (eine Beschreibung der Einschränkungen finden Sie in den git-clone-Dokumenten). –

3

Sie könnten die Verwendung von git submodules in Betracht ziehen. Auf diese Weise können Sie die Bilder und andere große Dateien in einem anderen Git-Repository aufbewahren, und das Repository mit den Quellcodes kann sich auf eine bestimmte Revision dieses anderen Repositorys beziehen.

Das hilft Ihnen, die Repository-Revisionen synchron zu halten, weil das übergeordnete Repository eine Verknüpfung zu einer bestimmten Unter-Repository-Revision enthält. Außerdem können Sie alte Revisionen im Unter-Repository entfernen/neu erstellen, ohne das übergeordnete Repository zu beeinflussen, in dem sich Ihr Quellcode befindet - das Entfernen alter Revisionen in einem Unter-Repository wird den Verlauf des übergeordneten Repositorys nicht beeinträchtigen, weil Sie einfach Aktualisieren Sie, auf welche Revision die Verknüpfung des Unter-Repository im übergeordneten Repository verweist.

+0

guter Punkt. Ich wusste nichts von Git-Submodulen. – neoneye

Verwandte Themen