Wie Gardenscapes einmal fast vereitelt wurde

Haftungsausschluss: Diese Geschichte ist vor einigen Jahren passiert. Aber es scheint, dass es immer noch nicht seine Relevanz verloren hat.





... Wir haben Gardenscapes entwickelt. Es hatte noch Spuren der alten Gartenlandschaften unter Windows. Es war nicht einmal Match-3, sondern ein Wimmelbild. Und niemand konnte sich vorstellen, welche Höhen das Spiel erreichen würde.



Und dann eines schönen Tages ...



Wie alles begann



Beim Zugriff auf das Repository wurde die folgende Meldung angezeigt:



„Dieses Repository wurde deaktiviert. Der Zugriff auf dieses Repository wurde von GitHub-Mitarbeitern aufgrund übermäßigen Ressourcenverbrauchs unter Verstoß gegen unsere Nutzungsbedingungen deaktiviert. Wenden Sie sich an den Support, um den Zugriff auf dieses Repository wiederherzustellen. Lesen Sie hier, um mehr über das Verringern der Größe Ihres Repositorys zu erfahren. "



Wie Sie vielleicht erraten haben, verwenden wir Github, um Git-Repositorys zu hosten. Und so blockierte Github plötzlich und ohne Kriegserklärung unser Repository, weil es die maximal zulässige Größe überschritten hatte. Die genaue Zahl auf ihrer Website wurde nicht angegeben. Zum Zeitpunkt des Sperrens war der .git-Ordner ungefähr 25 GB groß. (Hinweis 2020: Die Grenzwerte sind jetzt höher, und die Github-Site gibt ausdrücklich an, dass die Größe des Repositorys 100 GB nicht überschreiten sollte.)



Wie haben wir es geschafft, ein so großes Repository zu erstellen? Der Grund ist klar: Wir speichern darin Binärdateien. Überall steht geschrieben, dass dies nicht empfohlen wird, aber es ist viel einfacher für uns. Wir möchten, dass das Spiel ohne zusätzlichen Aufwand sofort aus dem Repository gestartet wird. Aus diesem Grund stellen wir Grafiken und andere Spielressourcen für das Repository bereit.



Das ist aber nicht so schlimm. Eine wichtige Lektion, die wir aus dieser ganzen Geschichte gelernt haben: Erzählen Sie niemals jemandem von Fight Club. Sie können keine Binärdateien mit häufig wechselnden Dateien in das Repository übertragen. Und wir haben dies getan: Wir haben die ausführbaren Datei- und Texturatlanten festgeschrieben. Jetzt sind wir sehr viel schlauer und haben Teamcity, das eine Binärdatei kompilieren und Atlanten erstellen kann, sowie spezielle Skripte, die all diese Dinge auf den Benutzer herunterladen. Aber das ist eine ganz andere Geschichte... Und für sehr große Dateien verwenden wir Git LFS, Google Drive und andere Vorteile der Zivilisation.



Kämpfe für die Geschichte



Also funktioniert nichts für irgendjemanden. Wir sagten dem Team, dass sie einen Tag vor Ort arbeiten müssten, sich aber nicht sehr anstrengen müssten, sonst würden sie Konflikte später klären (alle waren sehr verärgert und gingen sofort zum Tee). Und sie begannen zu überlegen, was sie tun sollten. Es ist klar, dass ein neues Repository benötigt wird, aber was soll dort festgelegt werden? Ein einfacher Weg ist der aktuelle Zustand aller Branchen. Aber es hat uns nicht so gut gefallen, weil die Geschichte der Veränderungen verloren gehen wird, der beliebteste Git-Schuldbefehl aller kaputt geht und alles in den Salto geht. Aus diesem Grund haben wir uns dazu entschlossen: Löschen Sie den Verlauf von Binärdateien und behalten Sie den Verlauf von Textdateien bei.





Schritt 1. Löschen Sie den Verlauf der Binärdateien



Wir hatten eine vollständige lokale Kopie des Repositorys. Das erste, was wir fanden, war das ausgezeichnete Dienstprogramm BFG Repo-Cleaner . Es ist sehr einfach und doch sehr schnell und der Titel ist gut.



Ein Beispiel für ein Ausführungsszenario:



java -jar bfg.jar bfg --delete-files *.{pvrtc,webp,png,jpeg,fla,swl,swf,pbi,bin,mask,ods,ogv,ogg,ttf,mp4} path_to_repository


Die Parameter enthalten alle Erweiterungen der Binärdateien, die wir uns einfallen lassen könnten. Bei allen Commits weltweit werden Informationen zu Dateien mit diesen Erweiterungen gelöscht. Das Dienstprogramm ist intelligent und verlässt beim Löschen des Verlaufs einer Datei die neueste Version. Darüber hinaus wird diese neueste Version in das letzte Commit für den Zweig aufgenommen. Wir wollten auch den Verlauf von exe- und dll-Dateien löschen, aber das Dienstprogramm gab einen Fehler aus. Anscheinend ist aus irgendeinem Grund die Verarbeitung in Form von * .exe verboten. Wenn Sie außerdem explizit eine Datei angeben, z. B. gardenscapes.exe, funktioniert alles. (Hinweis 2020: Der Fehler wurde möglicherweise bereits behoben.)



Schritt 2. Komprimieren Sie das Repository



Nach dem ersten Schritt ist das Repository immer noch groß. Der Grund dafür ist die Art und Weise, wie Git funktioniert. Wir haben nur Links zu Dateien entfernt, aber die Dateien selbst sind geblieben.



Um die Dateien physisch zu löschen, müssen Sie den Befehl git gc ausführen, nämlich:



git reflog expire --expire=now --all


 und dann:



git gc --prune=now --aggressive


Dies ist die vom Autor des Dienstprogramms empfohlene Befehlsfolge. Hier dauert gc wirklich lange. Darüber hinaus verfügt der Git-Client mit den Standard-Repository-Einstellungen nicht über genügend Speicher, um den Vorgang abzuschließen, und muss mit einem Tamburin getanzt werden. (Hinweis 2020: Zu dieser Zeit hatten wir eine 32-Bit-Version von git. Diese Probleme treten höchstwahrscheinlich nicht mehr in der 64-Bit-Version auf.)



Schritt 3. Schreiben von Commits in das neue Repository



Dies stellte sich als der interessanteste Teil der Suche heraus. 



Um zu verstehen, was folgt, müssen Sie verstehen, wie Git funktioniert. Sie können an vielen Stellen mehr über Git lesen, einschließlich unseres Blogs:



  1. Git: Tipps für Neulinge - Teil 1
  2. Git: Tipps für Neulinge - Teil 2
  3. Git: Tipps für Neulinge - Teil 3


Wir haben also sehr, sehr viele Commits vor Ort, diese Commits sind korrekt, dh ohne die Historie der Binärdateien. Es scheint, dass es ausreicht, Git Push auszuführen , und alles wird von selbst funktionieren. Aber nein!



Wenn Sie nur den Befehl git push -u master ausführenDann beginnt git fröhlich mit dem Hochladen von Daten auf den Server, stürzt jedoch mit einem Fehler von ca. 2 GB ab. Dies bedeutet, dass Sie nicht so viele Commits auf einmal hochladen können. Wir werden den Elefanten in Teilen essen. Wir gingen davon aus, dass 2.000 Commits wahrscheinlich in 2 GB passen würden. Das Gesamtvolumen unseres Repositorys betrug damals etwa 20.000 Commits, verteilt auf 4 Zweige: master-v101-v102-v103. (Anmerkung 2020: eh, Jugend! Seitdem ist alles viel ernster geworden. Es gibt bereits mehr als 100.000 Commits in diesem Repository und es gibt mehrere Dutzend Release-Zweige. Gleichzeitig passen wir immer noch in die Github-Grenzen.)



Zunächst betrachten wir die Anzahl der Commits in den Zweigen, wenn Hilfebefehl:



git rev-list --count <branch-name>


Beispielsweise gibt es in der Hauptniederlassung ungefähr 10.000 Commits. Jetzt können wir die erweiterte Syntax für den Befehl git push verwenden, nämlich:



git push -u origin HEAD~8000:refs/origin/master


HEAD ~ 8000: refs / origin / master ist die sogenannte refspec. Auf der linken Seite steht, dass Sie Commits bis zu einem Commit durchführen müssen, der 8.000 von HEAD entfernt ist, dh nur etwa 2.000 Commits. Und die rechte Seite ist, dass Sie sie in den Remote-Master-Zweig schieben müssen. Hier wird der vollständige Pfad zum Zweig refs / origin / master benötigt.



Danach gibt es noch keinen Hauptzweig, und beispielsweise kann git fetch ihn nicht herunterladen. Dies ist nicht überraschend - schließlich existiert das Commit, das auf ihren HEAD hinweist, noch nicht. Trotzdem haben wir beim Wiederholen des Befehls git push HEAD ~ 8000: refs / origin / master die Antwort gesehen, dass diese Commits bereits auf dem Server sind, und daher ist die Arbeit doch erledigt.



Als nächstes dachten wir, dass der Prozess klar ist und der Rest der Arbeit dem Skript zugewiesen werden kann. Das letzte Commit ist sehr umfangreich, da es alle Binärdateien enthält. Daher werden für alle Fälle die letzten 10 Commits separat ausgefüllt. Das Skript stellte sich wie folgt heraus:



git push origin HEAD~6000:refs/origin/master
git push origin HEAD~5000:refs/origin/master
git push origin HEAD~4000:refs/origin/master
git push origin HEAD~3000:refs/origin/master
git push origin HEAD~2000:refs/origin/master
git push origin HEAD~1000:refs/origin/master
git push origin HEAD~10:refs/origin/master
git push origin master
 
git checkout v101
 
git push -u origin HEAD~1000:refs/origin/v101
git push origin HEAD~10:refs/origin/v101
git push origin v101
 
git checkout v102
…  ..


Das heißt, wir schreiben konsistent alle unsere Zweige auf den Server, 2.000 Commits pro Push und die letzten 10 Commits separat.



Diese ganze Geschichte nahm viel Zeit in Anspruch und die Uhr wurde nachts gegen 12 Uhr gezeigt. Also ließen wir das Drehbuch über Nacht arbeiten, sprachen die richtigen Gebete zu Cthulhu (Anmerkung 2020: es war damals noch relativ beliebt) und gingen nach Hause. 



Das endgültige. Glückliches Ende



Am Morgen, nachdem wir das Repository auf der Github-Site geöffnet hatten, stellten wir sicher, dass das Skript erfolgreich funktionierte und alle Commits und Zweige vorhanden waren.



Infolgedessen wurde die Größe des Repositorys (.git-Ordner) von 25 GB auf 7,5 GB reduziert. Gleichzeitig bleibt der gesamte wichtige Commit-Verlauf - alles außer Binärdateien - erhalten. Die Spieledesigner tranken mehr Tee als gewöhnlich. Programmierer haben ein unvergessliches Erlebnis. Und sie begannen dringend darüber nachzudenken, wie es gemacht werden sollte, damit es nicht notwendig war, die ausführbare Datei in das Repository zu übertragen, aber es wäre bequem, damit zu arbeiten.



All Articles