Möglichkeiten zur Verbesserung der Git-Statusleistung

79

Ich habe ein Repo von 10 GB auf einem Linux-Computer, der auf NFS läuft. Das erste Mal git statusdauert 36 Minuten und das anschließende git statusdauert 8 Minuten. Git hängt anscheinend vom Betriebssystem ab, um Dateien zwischenzuspeichern. Nur die ersten gitBefehle wie commit, statusdass Pack beinhaltet / umpacken die ganze Repo eine sehr lange Zeit für eine riesige Repo nimmt. Ich bin mir nicht sicher, ob Sie git statusein so großes Repo verwendet haben, aber ist jemand auf dieses Problem gestoßen?

Ich habe versucht git gc, git clean, git repackaber die Zeit genommen , ist nach wie vor / fast gleich.

Helfen Submodule oder andere Konzepte wie das Aufteilen des Repos in kleinere? Wenn ja, welches ist das beste, um ein größeres Repo aufzuteilen? Gibt es eine andere Möglichkeit, die Zeit für Git-Befehle in einem großen Repo zu verbessern?

Senthil A Kumar
quelle
2
NFS ist hier so ziemlich der Engpass. lstat ist eine ziemlich synchrone Operation.
user611775
1
Mögliches Duplikat des Git-Status dauert lange
Seth Battin

Antworten:

45

Um genauer zu sein, hängt git von der Effizienz des lstat(2)Systemaufrufs ab. Daher kann es hilfreich sein, das "Attribut-Cache-Timeout" Ihres Clients zu optimieren.

Das Handbuch für git-update-index- im Wesentlichen ein manueller Modus für git-status- beschreibt, wie Sie dies beheben können, indem Sie das --assume-unchangedFlag verwenden , um das normale Verhalten zu unterdrücken und die von Ihnen geänderten Pfade manuell zu aktualisieren. Sie können Ihren Editor sogar so programmieren, dass dieses Flag bei jedem Speichern einer Datei deaktiviert wird.

Die Alternative besteht, wie Sie vorschlagen, darin, die Größe Ihrer Kasse zu reduzieren (die Größe der Packdateien kommt hier nicht wirklich ins Spiel). Die Optionen sind eine spärliche Kaufabwicklung, Submodule oder das Repo- Tool von Google .

(Es gibt einen Mailinglisten- Thread über die Verwendung von Git mit NFS , der jedoch nicht viele Fragen beantwortet.)

Josh Lee
quelle
31
Das, was Sie verpasst haben: Der dortige Linus-Patch wurde tatsächlich zusammengeführt und kann durch Setzen core.preloadindexauf true aktiviert werden. git-configEine ausführlichere Beschreibung finden Sie in den Dokumenten. (Mein Arbeitsplatz verwendet NFS, und ich bin genau auf dieses Problem
Cascabel
1
'git config core.preloadindex true' sollte hier zur akzeptierten Antwort hinzugefügt werden. möglicherweise mit dem Flag -uno von user1077329
ostler.c
1
core.preloadindexFlag ist standardmäßig ab Git 2.1.0
Petr Gazarov
38

Ich sehe dieses Problem auch bei einem großen Projekt, das über NFS geteilt wird.

Ich habe einige Zeit gebraucht , um das Flag -uno zu entdecken, das sowohl dem Git-Commit als auch dem Git-Status zugewiesen werden kann.

Mit diesem Flag wird die Suche nach nicht verfolgten Dateien deaktiviert. Dies reduziert die Anzahl der NFS-Operationen erheblich. Der Grund dafür ist, dass git, um nicht verfolgte Dateien zu erkennen, in allen Unterverzeichnissen suchen muss. Wenn Sie also viele Unterverzeichnisse haben, wird dies Ihnen schaden. Indem Sie git daran hindern, nach nicht verfolgten Dateien zu suchen, eliminieren Sie alle diese NFS-Vorgänge.

Wenn Sie dies mit dem Flag core.preloadindex kombinieren, erhalten Sie auch unter NFS eine resonante Leistung.

user1077329
quelle
Wie in git-status (1) erwähnt , kann es durch Einstellen der status.showUntrackedFilesKonfiguration als Standard festgelegt werden .
Johankj
32

Versuchen Sie es mit git gc . Auch Git Clean kann helfen.

UPDATE - Ich bin mir nicht sicher, woher die Abwertung stammt, aber im Git-Handbuch heißt es ausdrücklich:

Führt eine Reihe von Verwaltungsaufgaben im aktuellen Repository aus, z. B. das Komprimieren von Dateirevisionen (um den Speicherplatz zu reduzieren und die Leistung zu steigern ) und das Entfernen nicht erreichbarer Objekte, die möglicherweise aus früheren Aufrufen von git add erstellt wurden.

Benutzer werden aufgefordert, diese Aufgabe regelmäßig in jedem Repository auszuführen, um eine gute Speicherplatzauslastung und eine gute Betriebsleistung zu gewährleisten.

Ich bemerke immer einen Unterschied, nachdem ich git gc ausgeführt habe, wenn der git-Status langsam ist!

UPDATE II - Ich bin mir nicht sicher, wie ich das verpasst habe, aber das OP hat es bereits versucht git gcund git clean. Ich schwöre, das war ursprünglich nicht da, aber ich sehe keine Änderungen in den Änderungen. Das tut mir leid!

Jabari
quelle
4
Ich verstehe die Abwahl auch nicht; das ist wirklich hilfreich. git gcVerkürzen Sie die Zeit, um git logauf einem meiner Repos von 15 Sekunden auf 0 zu laufen.
GreenRaccoon23
@NicolasC Ah! Ich bin mir nicht sicher, wie ich das verpasst habe, aber ich würde meine Antwort auch dafür ablehnen. : - /
Jabari
1
git cg ist gut, git clean könnte vielleicht eine unerwünschte Datei löschen?
Luca Reghellin
18

Wenn Ihr Git-Repo stark von Submodulen Gebrauch macht, können Sie die Leistung des Git-Status erheblich beschleunigen, indem Sie die Konfigurationsdatei im Verzeichnis .git bearbeiten und ignore = dirtybesonders große / schwere Submodule festlegen. Zum Beispiel:

[submodule "mysubmodule"]
url = ssh://mysubmoduleURL
ignore = dirty

Sie verlieren die Bequemlichkeit einer Erinnerung daran, dass in einem der Submodule, die Sie möglicherweise vergessen haben, nicht bereitgestellte Änderungen vorgenommen wurden, behalten jedoch den Hauptkomfort bei, zu wissen, wann die Submodule nicht mit dem Haupt-Repo synchron sind. Außerdem können Sie Ihr Arbeitsverzeichnis weiterhin in das Submodul selbst ändern und den Git-Status wie gewohnt verwenden, um weitere Informationen anzuzeigen. In dieser Frage erfahren Sie mehr darüber, was "schmutzig" bedeutet.

Beno
quelle
7

Die Leistung des Git-Status sollte sich mit Git 2.13 (Q2 2017) verbessern.

Siehe Commit 950a234 (14. April 2017) von Jeff Hostetler ( jeffhostetler) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 8b6bba6 , 24. April 2017)

> string-list: Verwenden Sie bei der Neuzuweisung ein ALLOC_GROWMakrostring_list

Verwenden Sie ALLOC_GROW()Makro, wenn Sie ein string_listArray neu zuweisen, anstatt es einfach um 32 zu erhöhen.
Dies ist eine Leistungsoptimierung.

Während des Status eines sehr großen Repos und vieler Änderungen wird ein erheblicher Prozentsatz der Gesamtlaufzeit für die Neuzuweisung des wt_status.changesArrays aufgewendet .

Diese Änderung verringert die Zeit in wt_status_collect_changes_worktree()meinem sehr großen Repository von 125 Sekunden auf 45 Sekunden.


Außerdem wird Git 2.17 (Q2 2018) eine neue Ablaufverfolgung einführen, mit der gemessen werden kann, wo die Zeit für indexintensive Operationen aufgewendet wird.

Siehe Commit ca54d9b (27. Januar 2018) von Nguyễn Thái Ngọc Duy ( pclouds) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 090dbea , 15. Februar 2018)

trace: Messen Sie, wo die Zeit in den indexlastigen Operationen verbracht wird

Alle bekannten schweren Codeblöcke werden gemessen (außer Objektdatenbankzugriff). Dies sollte helfen, festzustellen, ob eine Optimierung effektiv ist oder nicht.
Ein nicht optimierter Git-Status würde ungefähr Folgendes ergeben:

0.001791141 s: read cache ...
0.004011363 s: preload index
0.000516161 s: refresh index
0.003139257 s: git command: ... 'status' '--porcelain=2'
0.006788129 s: diff-files
0.002090267 s: diff-index
0.001885735 s: initialize name hash
0.032013138 s: read directory
0.051781209 s: git command: './git' 'status'

Das gleiche Git 2.17 (Q2 2018) verbessert sich git statusmit:

revision.c: Objektdatenbankabfragen reduzieren

In mark_parents_uninteresting()überprüfen wir, ob eine Objektdatei vorhanden ist, um festzustellen, ob ein Commit als analysiert behandelt werden soll. Das Ergebnis ist das Setzen des "analysierten" Bits beim Festschreiben.

Ändern Sie die Bedingung, um nur zu überprüfen, has_object_file()ob das Ergebnis das analysierte Bit ändern würde.

Wenn sich eine lokale Niederlassung von ihrer vorgelagerten Referenz unterscheidet, git statusberechnet " " Voraus- / Rückwärtszählungen.
Dies verwendet paint_down_to_common()und trifft mark_parents_uninteresting().

Bei einer Kopie des Linux-Repos mit einer lokalen Instanz von "master" hinter dem Remote-Zweig " origin/master" um ~ 60.000 Commits wurde die Leistung von " git status" von 1,42 Sekunden auf 1,32 Sekunden erhöht, was einer relativen Differenz von -7,0% entspricht.


Git 2.24 (Q3 2019) schlägt eine andere Einstellung vor, um die git statusLeistung zu verbessern :

Siehe Commit aaf633c , Commit c6cc4c5 , Commit ad0fb65 , Commit 31b1de6 , Commit b068d9a , Commit 7211b9e (13. August 2019) von Derrick Stolee ( derrickstolee) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit f4f8dfe , 9. September 2019)

Repo-Einstellungen: Erstellen Sie die Einstellung feature.manyFiles

Die feature.manyFilesEinstellung eignet sich für Repos mit vielen Dateien im Arbeitsverzeichnis.
Durch Setzen von index.version=4und core.untrackedCache=truesollten Befehle wie ' git status' verbessert werden.

Aber:

Mit Git 2.24 (Q4 2019) wurde der Codepfad, der die index.versionKonfiguration liest, durch ein kürzlich korrigiertes Update unterbrochen.

Siehe Commit c11e996 (23. Oktober 2019) von Derrick Stolee ( derrickstolee) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 4d6fb2b , 24. Oktober 2019)

repo-settings: Lesen Sie ein Int für index.version

Unterzeichnet von: Derrick Stolee

Mehrere Konfigurationsoptionen wurden repo_settingsin ds / feature-macros zu einer Struktur kombiniert , einschließlich einer Verschiebung der Konfigurationseinstellung "index.version" in 7211b9e (" repo-settings: Einige Konfigurationseinstellungen konsolidieren", 2019-08-13, Git v2.24.0-rc1 - Zusammenführung in Charge Nr. 0 ).

Leider sah diese Datei wie eine Menge Boilerplate aus und was eindeutig ein Faktor für die Überladung durch Kopieren und Einfügen ist, ist, dass die Konfigurationseinstellung repo_config_ge_bool()anstelle von analysiert wird repo_config_get_int(). Dies bedeutet, dass eine Einstellung "index.version = 4" nicht korrekt registriert und auf die Standardversion von 3 zurückgesetzt wird.

Ich habe dies festgestellt, als ich v2.24.0-rc0 in die VFS for Git-Codebasis integriert habe, wobei es uns wirklich wichtig ist, dass der Index in Version 4 enthalten ist.

Dies wurde von der Codebasis nicht erfasst, da die eingegebenen Versionsprüfungen t1600-index.shdas "grundlegende" Szenario nicht ausreichend testeten. Hier ändern wir den Test so, dass diese normalen Einstellungen nicht von features.manyFilesoder überschrieben werden GIT_INDEX_VERSION.
Während die "Standard" -Version 3 ist, wird diese in Version 2 herabgestuft, do_write_index()wenn dies nicht erforderlich ist.

VonC
quelle
Siehe auch stackoverflow.com/a/43667992/6309 und die neue index.threadsKonfigurationseinstellung
VonC
GIT_TRACE = true git log So führen Sie trace aus und finden einen Engpass
dhavale
@dhavale Eigentlich haben Sie seit Git .22 auch trace2: stackoverflow.com/a/56094711/6309
VonC
3

git config --global core.preloadIndex true

Hat den Job für mich gemacht. Überprüfen Sie die offizielle Dokumentation hier .

klimat
quelle
Welche Version von Git verwenden Sie?
VonC
2.7.4. Ich benutze Linux Subsystem für Windows und selbst aktualisiert apt-getscheint Verweise auf ziemlich alte Pakete zu haben.
klimat
1
Ok, mach Sinn. Ich denke nicht, dass es mit einer neueren Version benötigt wird.
VonC
Dies half mir sogar mit Git-Version 2.17.1
Markus Zeller
1

In unserer Codebasis, in der wir irgendwo im Bereich von 20 bis 30 Submodulen haben, haben sich
git status --ignore-submodules
die Dinge für mich drastisch beschleunigt. Beachten Sie, dass dies nicht über den Status von Submodulen berichtet .

Stadt umgeben
quelle
1

Was noch nicht erwähnt wurde, ist, den Dateisystem-Cache auf Windows-Computern zu aktivieren (Linux-Dateisysteme sind völlig anders und Git wurde für sie optimiert, daher hilft dies wahrscheinlich nur unter Windows).

git config core.fscache true


Als letztes Mittel, wenn Git immer noch langsam ist, könnte man die Überprüfung der Änderungszeit deaktivieren, damit Git herausfinden kann, welche Dateien sich geändert haben.

git config core.ignoreStat true

ABER: Geänderte Dateien müssen anschließend vom Entwickler selbst mit hinzugefügt werden git add. Git findet selbst keine Änderungen.

Quelle

dCSeven
quelle
Dies hat mir unter Windows 10 geholfen, obwohl ich eine ziemlich aktuelle Version von Git für Windows hatte. Vielen Dank. Mein Repo war ~ 100 GB im .git-Ordner (git lfs)
Alex Sorokoletov
0

Übrig gebliebene index.lockDateien

git statuskann pathologisch langsam sein, wenn Sie übrig gebliebene index.lockDateien haben.

Dies geschieht insbesondere dann, wenn Sie git submodulessolche Lefterover-Dateien häufig nicht bemerken.

Zusammenfassung: Führen Sie find .git/ -name index.lockdie verbleibenden Dateien aus und löschen Sie sie, nachdem Sie überprüft haben, ob sie tatsächlich von keinem aktuell ausgeführten Programm verwendet werden.


Einzelheiten

Ich fand, dass mein Shell-Git-Status in meinem Repo extrem langsam war, mit Git 2.19 unter Ubuntu 16.04.

Eingegraben und festgestellt, dass /usr/bin/time git statusin meinem assetsGit-Submodul 1,7 Sekunden dauerte.

Gefunden mit stracediesem Git lesen alle meine großen Dateien dort mit mmap. Das macht es normalerweise nicht, normalerweise statist es genug.

Ich habe das Problem gegoogelt und das Problem mit der Verwendung von Index und Racy Git gefunden .

Versucht git update-index somefile(in meinem Fall gitignorein der Submodul-Kasse) hier gezeigt , aber es ist fehlgeschlagen mit

fatal: Unable to create '/home/niklas/src/myproject/.git/modules/assets/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.

Dies ist ein klassischer Fehler. Normalerweise bemerken Sie es bei jeder Git-Operation, aber bei Submodulen, auf die Sie sich nicht oft festlegen, bemerken Sie es möglicherweise monatelang nicht, da es nur angezeigt wird, wenn Sie dem Index etwas hinzufügen. Die Warnung wird nicht schreibgeschützt ausgelöst git status.

Das Entfernen der index.lockDatei git statuswurde sofort schnell, mmapsverschwand und ist jetzt über 1000x schneller.

Wenn Ihr Git-Status unnatürlich langsam ist, überprüfen find .git/ -name index.lockund löschen Sie die Reste.

nh2
quelle
0

Es ist eine ziemlich alte Frage. Ich bin jedoch überrascht, dass sich angesichts der Repository-Größe niemand zu einer Binärdatei geäußert hat.

Sie haben erwähnt, dass Ihr Git-Repo ~ 10 GB beträgt. Abgesehen von NFS-Problemen und anderen Git-Problemen (behebbar durch git gcund Änderung der Git-Konfiguration als Umriss in anderen Antworten) scheinen Git-Befehle (Git-Status, Git-Diff, Git-Add) aufgrund der großen Anzahl von Binärdateien im Repository langsam zu sein . Git ist nicht gut im Umgang mit Binärdateien. Sie können unnötige Binärdateien mit dem folgenden Befehl entfernen (Beispiel für NetCDF-Datei; Sicherung des Git-Repositorys vorher):

git filter-branch --force --index-filter \  
'git rm --cached --ignore-unmatch *.nc' \   
--prune-empty --tag-name-filter cat -- --all

Vergessen Sie nicht, '* .nc' in die gitignore-Datei einzufügen, um zu verhindern, dass git die Datei erneut festlegt.

MS_
quelle