68 votes

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

J'ai un "nouveau" git-svn repo (11.13 GB) qui a plus de 100 000 objets à l'intérieur.

J'ai préformé

git fsck
git gc

sur le repo après la période initiale de la caisse.

J'ai ensuite essayé de faire un

git status

Le temps qu'il faut pour faire un git status est n'importe où à partir de 2m25.578s et 2m53.901s

J'ai testé git status par l'émission de la commande

time git status

5 fois et toutes les fois couru entre les deux horaires indiqués ci-dessus.

Je suis en train de faire sur un Mac OS X, localement non pas grâce à une VM.

Il n'existe aucun moyen il convient de prendre ce long.

Des idées? De l'aide?

Merci.

Modifier

J'ai un collègue assis à côté de moi avec un comparable de la boîte. Moins de RAM et sous Debian avec un système de fichiers jfs. Son git status s'exécute dans .3 sur le même repo (c'est aussi un git-svn checkout).

Aussi, j'ai récemment changé mon fichier permissions (777) sur ce dossier et il a apporté à la fois une baisse considérable (pourquoi, j'en sais rien). Je peux maintenant le faire n'importe où entre 3 et 6 secondes. C'est gérable, mais toujours une douleur.

35voto

mediaslave Points 1152

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.

21voto

masonk Points 1572

git status a qu'à regarder à chaque fichier dans le référentiel de tous les temps. Vous pouvez le dire d'arrêter de regarder les arbres que vous ne travaillez pas avec

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

source

À partir de la page de manuel:

Lorsque ces indicateurs sont spécifiés, la les noms d'objets enregistrés pour les chemins ne sont pas mis à jour. Au lieu de cela, ces les options de jeu et de désactiver la "assumer inchangé" bits pour les chemins. Lorsque l' "supposons inchangé" bit est sur, git arrête le contrôle du travail de l'arborescence de fichiers pour d'éventuelles modifications, de sorte que vous besoin de désactiver manuellement le peu de dire git lorsque vous modifiez l'arbre de travail fichier. C'est parfois utile lorsque travailler avec un grand projet sur un système de fichiers qui a très lent lstat(2) système d'appel (par exemple, cifs).

Cette option peut également être utilisé comme un grossier fichier mécanisme au niveau de l'ignorer les modifications non validées dans le suivi des fichiers (semblable à ce que .gitignore pour sans traces de fichiers). Git va échouer (gracieusement) dans le cas où il doit modifier ce fichier dans l'index par exemple lors de la fusion dans un commit; ainsi, dans cas de l'hypothèse-sans traces de fichier est changé en amont, vous aurez besoin de face à la situation manuellement.

De nombreuses opérations de git dépendent de votre système de fichiers efficace lstat(2) la mise en œuvre, de sorte que st_mtime informations pour l'arbre de travail les fichiers peuvent être bon marché vérifié pour voir si le contenu de ce fichier ont changé de la version enregistrée dans l'index fichier. Malheureusement, certains systèmes de fichiers ont inefficace lstat(2). Si votre système de fichiers est l'un d'entre eux, vous pouvez définir "supposons inchangé" peu de chemins n'ont pas changé à cause git de ne pas faire cette vérification. Notez que la définition de ce bits sur un chemin d'accès ne signifie pas git va vérifiez le contenu du fichier pour voir si elle a changé - il fait que git omettre aucune vérification et de supposer qu'il a pas changé. Lorsque vous apportez des modifications à de travail de l'arborescence de fichiers, vous devez explicitement indiquer à git à ce sujet par lâchant "assumer inchangé" peu, que ce soit avant ou après la modification eux.

...

Afin de mettre en "assumer inchangé" bits, utilisez --assume-inchangé option. Pour unset, utilisez l'option --no-supposons-inchangé.

La commande est à la base.ignorestat variable de configuration. Lorsque cela est vrai, les chemins de mise à jour avec git mise à jour de l'index des chemins... et les chemins de mise à jour avec d'autres commandes git que la mise à jour les deux index et de l'arbre de travail (par exemple, git s'appliquer, index, git checkout-index-u, et git lecture de l'arbre -u) sont automatiquement marqué comme "assumer inchangé". À noter que "l'assumer inchangé" bit n'est pas défini si git mise à jour de l'index --refresh trouve le de travail de l'arborescence de fichier correspond à l'indice de (l'utilisation de git update-index-vraiment-actualisation si vous souhaitez marquer comme "assumer stable").


Maintenant, clairement, cette solution n'est d'aller travailler si il y a des parties de l'opération que vous pouvez facilement ignorer. Je travaille sur un projet de taille similaire, et il y a certainement de grands arbres que je n'ai pas besoin de vérifier sur une base régulière. La sémantique de git-le statut en faire un général O(n) problème (n nombre de fichiers). Vous avez besoin d'un domaine spécifique des optimisations à faire mieux que ça.

Notez que si vous travaillez dans une configuration de couture, qui est, si vous intégrer des modifications de l'amont par fusion au lieu de cela, alors cette solution devient de moins en moins pratique, en raison d'une modification à un --assume-inchangé objet de la fusion dans de l'amont devient un conflit de fusion. Vous pouvez éviter ce problème avec un rebasage de flux de travail.

5voto

Chris Kline Points 87

Une solution à plus long terme est d'accroître git pour le cache du système de fichiers d'état à l'interne.

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

Karsten changements: 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

3voto

Brendon Points 146

Pour ce que ça vaut, j'ai récemment trouvé une grande écart entre le git status commande entre mon maître et dev branches.

Pour couper une longue histoire courte, j'ai traqué le problème à une seule 280 MO fichier dans le répertoire racine du projet. Il a été un accident de l'archivage d'un dump de la base, donc c'était bien de le supprimer.

Voici l'avant et l'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 de 105 000 objets dans le magasin, mais il semble que les fichiers volumineux sont plus une menace que de nombreux petits fichiers.

2voto

David Underhill Points 9356

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

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X