Gegebenes folgendes Szenario.
Meine Erwartungen sind, dass die bereits hochgeladenen Dateien nicht erneut mit git push
hochgeladen werden. Aber was wirklich passiert, ist, dass wenn eine neue Verzweigung gemacht wird, alle Dateien (auch wenn Tausende kleinerer Quelldateien statt einer 10MB Datei) immer wieder hochgeladen werden.
Meine Frage: Wie kann ich erreichen, dass Git erkennt, dass die 10-MB-Datei bereits hochgeladen wurde? Kennen Sie eine Problemumgehung, damit Git bereits vorhandene Objekte auf dem Server erkennt, wenn Sie Commits durchführen? Git erkennt Dateien anhand seines sha. Es sollte also erkennen können, dass einige Dateien in der Baumstruktur des Commits bereits auf dem Server vorhanden sind.
Möglicher Anwendungsfall: Ich habe zwei völlig verschiedene Zweige, aber einige gemeinsame Dateien werden innerhalb dieser beiden geteilt. Wenn ich einen Zweig drücke, möchte ich die gemeinsamen Dateien nicht erneut hochladen, wenn ich den zweiten Zweig drücke.
Tatsächlicher Anwendungsfall: Ich mache viele maschinelle Lernexperimente mit Python-Skripten und einigen kleineren Datensätzen (1MB - 10MB). Jedes Mal, wenn ich ein Experiment starte, füge ich alle notwendigen Experimentdateien zu einem neuen Git-Baum hinzu und verwende diesen Baum in einem neuen Commit ohne Verzweigung. Dieses Commit hängt völlig frei in der Luft und wird dann mit einer neuen Git-Referenz referenziert (z.B. refs / jobs / my-experiment-name). Wenn ich jetzt zwei Experimente mit fast den gleichen Dateien (und somit zwei Referenzen) habe, schiebt Git alle Objekte erneut, wenn ich diese Referenzen verschiebe. Ich habe eine geringe Bandbreite und das verlangsamt meine Arbeit wirklich.
%Vor%Auf der technischen Seite haben wir:
Die Lösung ist leider nicht so einfach.
Jedes Mal, wenn Git zwei Repositories synchronisieren möchte, erstellt es eine Paketdatei, die alle notwendigen Objekte (wie Dateien, Commits, Bäume) enthält. Wenn Sie git push
ausführen, sendet die Gegenstelle alle vorhandenen Referenzen (Zweige), und ihr Kopf sendet SHA an den Client. Dies ist das Problem: Das Paketprotokoll ist nicht zur Verwendung gedacht per-Objekt, aber per-commit.
Entsprechend dem Protokoll selbst ist das oben erläuterte Verhalten korrekt. Um das zu umgehen, habe ich ein einfaches Skript erstellt, mit dem jeder git push
basierend auf Objekten anstelle von Commits erstellen kann.
Sie finden es hier: Ссылка
Was es macht:
Natürlich hat das einige Nachteile, aber ich habe sie im verlinkten Github-Repository beschrieben.
Mit meinem obigen Skript bekommen Sie jetzt folgendes:
%Vor% Wie Sie sehen, wird nur ein Objekt (das Commit-Objekt) und nicht die dummy
-Datei und ihr Baumobjekt erneut synchronisiert.
Git entwickelt seine Manifeste und verpackt Objekte mit nur einem Austausch von Referenzen. Wenn der Zweig, den du schiebst, keine gemeinsamen Vorfahren mit der Fernbedienung hat, wird er alle Objekte, die von diesem Zweig erreichbar sind, packen und erneut hochladen.
Die Sequenz läuft ungefähr so ab
Die Fernbedienung erkennt bereits in ihrer Datenbank vorhandene Objekte und verwendet die vorhandenen Objekte.
Die Logik besteht darin, dass das Senden von ein paar unnötigen Dateien von Zeit zu Zeit weitaus effizienter ist als das Durchlaufen des gesamten Verlaufs (möglicherweise Zehntausende oder Hunderttausende von Objekten, auf die zugegriffen und verglichen wird) bei jedem Push.
Ich denke, Sie müssen nicht mehr --orphan
verwenden, um neue Experiment-Zweige zu erstellen.
Workflow
Das ist es.
Was ist los?
Sie haben darauf bestanden, dass Sie keine Zweige verwenden und dass Sie nur Referenzen verwenden. Branchen sind jedoch eine Art Referenz . Darüber hinaus erstellt git checkout --orphan <newthing>
tatsächlich einen Zweig . Das Problem ist, dass es ein Zweig ist, der nichts weiß, was zuvor dem Repository hinzugefügt wurde, weil es keine Eltern hat. Es ist im Wesentlichen das Gleiche, als hätte man ein ganz neues Repository erstellt.
Wenn Sie neue Zweige mit git checkout -b <newthing> master
erstellen, stört git nicht die hochgeladenen Dateien, die bereits in master waren.
Wie verwalten Sie jetzt neue gemeinsame Dateien?
Nehmen wir an, Sie haben eines Tages eine neue Datei, die alle zukünftigen Experimente nutzen sollen - eine neue gemeinsame / gemeinsame Datei. Alles, was Sie tun müssen, ist, diese Datei zu master
hinzuzufügen und Ihren nächsten Experimentzweig basierend auf dem aktualisierten Masterzweig zu erstellen. Wenn diese Datei für Ihre vorhandenen / zuvor erstellten Tests verfügbar sein soll, müssen Sie nur diese Zweige auschecken und git pull --rebase origin master
ausführen. Dies würde die Commits, die Sie dem Master hinzugefügt haben, einziehen, die die neu hinzugefügten Dateien enthalten würden.
Montagekomplexität
Wenn Sie mit dem Ziehen beginnen, werden die Dinge vielleicht kompliziert. Es gibt ein paar verschiedene Strategien zum Aktualisieren von Zweigen, und die Verwendung von --rebase
ist eine dieser Strategien. Es ist nicht erforderlich, aber es ist wahrscheinlich der bessere Weg. Es gibt noch weitere Dinge, die zu berücksichtigen sind, z. B. die Behandlung von widersprüchlichen Änderungen, die jedoch außerhalb des Bereichs dieser Frage liegen. Es gibt genügend Ressourcen, um das Rebasing / Merging etc. zu erklären.
TR; DR
Versuchen Sie nicht, Commit-Bäume und Eltern / Kind-Beziehungen manuell zu verwalten. Lass einfach git
sein Ding machen.
Tatsächlicher Anwendungsfall: Ich mache viele maschinelle Lernexperimente mit Python-Skripten und einigen kleineren Datensätzen (1MB - 10MB). Jedes Mal, wenn ich ein Experiment starte, füge ich alle notwendigen Experimentdateien zu einer neuen Git-Struktur hinzu
Das scheint weniger ein git-bezogenes Problem zu sein und mehr ein Content-Management-Problem: Wenn Sie einen gemeinsamen Satz statischer Dateien haben, die Sie von einem Git-Repo-Zweig in einen anderen Zweig wiederverwenden wollen, der Satz von Dateien (der sich nie ändert) muss nicht unbedingt im Git Repo sein.
Sie könnten in Erwägung ziehen, es in einem statischen Pfad auf einem Server hochzuladen und sicherzustellen, dass Ihr ML-Skript (versioniert in Ihrem Git-Repository) seinen Lernprozess startet, indem es diesen anfänglichen Datensatz aus dem statischen Pfad holt und kopiert Oder sie könnten in ihrem eigenen Git Repo sein, und Ihr Skript würde damit beginnen, den Unterordner, der diesen Daten gewidmet ist, durch Klonen / Ziehen von diesem externen Repo zu klonen / aktualisieren.
Auf diese Weise umgehen Sie das Versionskontrollproblem und nur die Version (in Ihrem Multi-Branch Repo, die Ihren Experimenten gewidmet ist), was tatsächlich von Commit zu Commit wechseln kann: Ihre ML-Skripte und möglicherweise einige spezifische (und kleinere) ) Datensätze, zugeschnitten auf neue Experimente.
Es könnte besser sein, Git LFS in Ihrem Szenario zu verwenden. Git LFS wurde für die Verwaltung großer Dateien in Git-Repositories entwickelt.
Gemäß diesem GitHub-Problem (mit wurde aufgelöst ~ vor 2 Jahren, doppelte Dateien werden als eine einzelne Entität mit derselben OID verwaltet. So werden sie nur einmal gedrückt und nur einmal abgerufen.
Mindestens Github und Gitlab enthalten bereits Unterstützung für git-lfs in allen Repositories.
Wie andere bereits erwähnt haben; Git sucht nur nach Blobs in dem Zweig, den du schiebst, aber du kannst Git dazu bringen, nach Blobs im Master-Zweig zu suchen, indem du es in deine Vorfahren einfügst.
Es scheint, dass Sie wirklich an einem verwaisten Zweig arbeiten möchten, so dass Sie den Master-Zweig nur zusammenführen können, wenn Sie pushen möchten. Sie können den gesamten Inhalt des Master-Zweiges ignorieren, indem Sie die ours
-Strategie verwenden.
Der Inhalt ist genau der gleiche:
%Vor%Wenn Sie sich nicht mit Ihrem ursprünglichen Zweig anlegen möchten, können Sie einen neuen Zweig nur für das Drücken erstellen.
Außerdem kannst du einfach mit dem Master anfangen und einfach alle Dateien wegwerfen:
%Vor%Wenn Sie wirklich möchten, dass dieser recht spezifische Anwendungsfall in Git richtig gehandhabt wird, können Sie die Entwickler auf der Mailingliste kontaktieren . Sie könnten Ihnen andere Alternativen anbieten, aber es ist möglich, dass sie nicht zustimmen, dass es etwas gibt, das im Code verbessert werden kann, ohne dass es in anderen Fällen zu erheblichen Kompromissen kommt.
Hinweis : Ich weiß nicht, warum Sie die Dummy-Datei in Ihren Schritten hinzufügen mussten, auf meiner Seite wird der gesamte Inhalt des Master-Zweigs inszeniert, wenn ich git checkout --orphan
mache.