web-dev-qa-db-fra.com

Git est vraiment lent pour 100 000 objets. Des correctifs?

J'ai un "nouveau" repo git-svn (11,13 Go) qui contient plus de 100 000 objets.

J'ai préformé

git fsck
git gc

sur le repo après la caisse initiale.

J'ai ensuite essayé de faire un

git status

Le temps qu'il faut pour faire un statut de git est compris entre 2m25.578s et 2m53.901s

J'ai testé le statut de git en lançant la commande

time git status

5 fois et tous les temps écoulés entre les deux temps indiqués ci-dessus.

Je le fais sur un Mac OS X, pas localement via une machine virtuelle.

Il ne faut pas que ça prenne autant de temps.

Des idées? Aidez-moi?

Merci.

Modifier

J'ai un collègue assis à côté de moi avec une boîte comparable. Moins RAM et l'exécution de Debian avec un système de fichiers jfs. Son git status s’exécute en .3 sur le même dépôt (c’est aussi une extraction git-svn).

De plus, j'ai récemment changé les autorisations de mon fichier (777) sur ce dossier, ce qui a considérablement réduit le temps (pourquoi, je n'ai aucune idée). Je peux maintenant le faire n'importe où entre 3 et 6 secondes. Ceci est gérable, mais reste une douleur.

52
manumoomoo

Cela se résumait à quelques éléments que je peux voir maintenant.

  1. git gc --aggressive
  2. Ouverture des autorisations de fichiers à 777

Il doit y avoir autre chose, mais c’est ce qui a clairement eu le plus grand impact.

28
manumoomoo

le statut git doit examiner chaque fichier du référentiel à chaque fois. Vous pouvez lui dire d'arrêter de regarder les arbres avec lesquels vous ne travaillez pas 

git update-index --assume-unchanged <trees to skip>

la source

De la page de manuel:

Lorsque ces indicateurs sont spécifiés, le noms d'objets enregistrés pour les chemins ne sont pas mis à jour. Au lieu de cela, ceux-ci les options définissent et annulent le bit "assumer inchangé" pour les chemins. Quand le le bit "suppose inchangé" est activé, git arrête de vérifier les fichiers d'arbre de travail pour d'éventuelles modifications, de sorte que vous besoin de désactiver manuellement le bit pour dire git quand vous changez l’arbre de travail fichier. Ceci est parfois utile lorsque travailler avec un grand projet sur un système de fichiers qui a une très lente lstat (2) appel système (par exemple, cifs).

Cette option peut également être utilisée en tant que mécanisme grossier au niveau des fichiers à ignorer modifications non validées dans les fichiers suivis (comme ce que fait .gitignore pour les fichiers non suivis). Git va échouer (gracieusement) au cas où il le faudrait modifiez ce fichier dans l'index, par exemple . lors de la fusion dans un commit; ainsi, dans Si le fichier supposé non suivi est changé en amont, vous devrez gérer la situation manuellement.

De nombreuses opérations dans git dépendent de votre système de fichiers pour avoir un efficace lstat (2), de sorte que Informations st_mtime pour l’arbre de travail les fichiers peuvent être vérifiés à moindre coût pour voir si le contenu du fichier a changé depuis la version enregistrée dans l'index fichier. Malheureusement, certains systèmes de fichiers lstat inefficace (2). Si ton Le système de fichiers en est un, vous pouvez définir "suppose inchangé" bit aux chemins vous n'ont pas changé pour que git ne le fasse pas faire cette vérification. Notez que ce paramètre mord sur un chemin ne veut pas dire git will vérifiez le contenu du fichier pour voir si cela a changé - cela rend git à omettez toute vérification et supposez qu'elle a inchangé. Lorsque vous apportez des modifications à fichiers d'arbre de travail, vous devez explicitement en parler à git par chute du bit "supposer inchangé", soit avant ou après avoir modifié leur.

...

Pour définir "suppose inchangé" peu, utilisez l'option --assume-non modifiée. À non défini, utilisez --no-assume-inchangé.

La commande examine core.ignorestat variable de configuration. Quand c'est true, les chemins mis à jour avec git chemins de mise à jour-index… et chemins mis à jour avec d’autres commandes git qui mettent à jour l’index et l’arbre de travail (par exemple, git apply --index, git checkout-index -u, et git read-tree -u) sont des éléments marqué automatiquement comme "suppose inchangé". Notez que le bit "suppose Unchanged" n'est pas activé si git update-index --refresh trouve le Le fichier d'arbre de travail correspond à l'index (utilisez git update-index --really-refresh si vous souhaitez les marquer comme "suppose inchangé").


Il est clair que cette solution ne fonctionnera que si vous pouvez facilement ignorer certaines parties du référentiel. Je travaille sur un projet de taille similaire, et il y a définitivement de grands arbres que je n'ai pas besoin de vérifier régulièrement. La sémantique de git-status en fait un problème généralement O(n) (n en nombre de fichiers). Vous avez besoin d'optimisations spécifiques à un domaine pour faire mieux que cela.

Notez que si vous travaillez dans un schéma d'assemblage, c'est-à-dire si vous intégrez des modifications de l'amont par fusion plutôt que par refonte, cette solution devient moins pratique, car la modification d'un objet --assume-inchangé fusionné depuis l'amont devient une fusion conflit. Vous pouvez éviter ce problème avec un workflow de rebasement.

17
masonk

Une solution à long terme consiste à augmenter la capacité de git de mettre en cache le statut du système de fichiers en interne. 

Karsten Blees l'a fait pour msysgit, ce qui améliore considérablement les performances sous Windows. Dans mes expériences, son changement a pris le temps pour "l'état de git" de 25 secondes à 1 à 2 secondes sur mon ordinateur Win7 s'exécutant sur une machine virtuelle.

Les changements de Karsten: https://github.com/msysgit/git/pull/94

Discussion de l'approche de mise en cache: https://groups.google.com/forum/#!topic/msysgit/fL_jykUmUNE/discussion

5
Chris Kline

En général, mon mac est ok avec git mais s'il y a beaucoup d'objets en vrac, cela devient beaucoup plus lent Il semble que hfs n’est pas si bon avec beaucoup de fichiers dans un seul répertoire.

git repack -ad

Suivi par

git gc --Prune=now

Crée un fichier de pack unique et supprime tous les objets en vrac. Cela peut prendre un certain temps pour les exécuter.

4
slobobaby

Vous pouvez essayer de passer le commutateur --aggressive à git gc et voir si cela vous aide:

# this will take a while ...
git gc --aggressive

De même, vous pouvez utiliser git filter-branch pour supprimer les anciens commits et/ou fichiers si vous avez des éléments inutiles dans votre historique (par exemple, les anciens fichiers binaires).

3
David Underhill

Pour ce que cela vaut, j'ai récemment constaté un écart important entre la commande git status entre mon maître et les branches dev. 

Pour résumer, j'ai retracé le problème dans un seul fichier de 280 Mo situé dans le répertoire racine du projet. Il s’agissait d’un enregistrement accidentel d’un dump de base de données, il était donc préférable de le supprimer.

Voici l'avant et après:

⚡ time git status
# On branch master
nothing to commit (working directory clean)
git status  1.35s user 0.25s system 98% cpu 1.615 total

⚡ rm savedev.sql

⚡ time git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   deleted:    savedev.sql
#
no changes added to commit (use "git add" and/or "git commit -a")
git status  0.07s user 0.08s system 98% cpu 0.157 total

J'ai 105 000 objets en magasin, mais il semble que les gros fichiers constituent plus une menace que de nombreux petits fichiers.

2
Brendon McLean

Vous pouvez également essayer git repack

1
baudtack

Peut-être utilisez-vous un scanner de virus? J'ai testé de gros projets ici sous Windows et Linux - c'était sacrément rapide!

Je ne pense pas que vous ayez besoin de faire un git gc dans un repo cloné (il devrait être propre).

Votre disque dur est-il OK? IOPS et R/W par seconde? Peut-être qu'il est endommagé?

0
Andreas Rehm

spotlight essaie peut-être d’indexer les fichiers. Peut-être désactiver Spotlight pour votre répertoire de code. Vérifiez le moniteur d'activité et voyez quels processus sont en cours d'exécution.

0
neoneye

Essayez d'exécuter la commande Prune, il va se débarrasser des objets

git remote Prune Origin

0
Devnegikec

Je créerais une partition en utilisant un système de fichiers différent. HFT + a toujours été lent pour moi par rapport à la réalisation d'opérations similaires sur d'autres systèmes de fichiers.

0
srparish