web-dev-qa-db-fra.com

Git - comment lister TOUS les objets dans la base de données

Existe-t-il un meilleur moyen d'obtenir une liste brute de SHA1 pour TOUS les objets dans un référentiel que de faire ls .git/objects/??/\* et cat .git/objects/pack/*.idx | git show-index?

Je connais git rev-list --all mais qui ne répertorie que les objets commit référencés par .git/refs, et je recherche tout y compris les objets non référencés qui sont créés par git-hash-object, git-mktree etc.

51
kbro

Modifier: Aristote publié ne réponse encore meilleure , qui devrait être marqué comme correct.

Edit: le script contenait une erreur de syntaxe, une barre oblique inversée manquante à la fin du grep -v ligne

La réponse de Mark a fonctionné pour moi, après quelques modifications:

  • Utilisé --git-dir au lieu de --show-cdup pour prendre en charge les dépôts nus
  • Erreur évitée lorsqu'il n'y a pas de packs
  • Perl utilisé car le style BSD d'OS X Mountain Lion sed ne prend pas en charge -r
#!/bin/sh

set -e

cd "$(git rev-parse --git-dir)"

# Find all the objects that are in packs:

find objects/pack -name 'pack-*.idx' | while read p ; do
    git show-index < $p | cut -f 2 -d ' '
done

# And now find all loose objects:

find objects/ \
    | egrep '[0-9a-f]{38}' \
    | grep -v /pack/ \
    | Perl -pe 's:^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}):\1\2:' \
;
9
willkil

Essayer

 git rev-list --objects --all

Edit Josh a fait un bon point:

 git rev-list --objects -g --no-walk --all

liste les objets accessibles à partir des journaux de référence.

Pour voir également tous les objets dans les validations inaccessibles:

 git rev-list --objects --no-walk \
      $(git fsck --unreachable |
        grep '^unreachable commit' |
        cut -d' ' -f3)

Tout mettre ensemble, pour vraiment obtenir tous les objets au format de sortie de rev-list --objects, vous avez besoin de quelque chose comme

{
    git rev-list --objects --all
    git rev-list --objects -g --no-walk --all
    git rev-list --objects --no-walk \
        $(git fsck --unreachable |
          grep '^unreachable commit' |
          cut -d' ' -f3)
} | sort | uniq

Pour trier la sortie de manière légèrement plus utile (par chemin pour l'arborescence/les blobs, valide d'abord), utilisez un | sort -k2 qui regroupera tous les différents blobs (révisions) pour des chemins identiques.

35
sehe

Je ne sais pas depuis quand cette option existe mais vous pouvez

git cat-file --batch-check --batch-all-objects

Cela vous donne, selon la page de manuel,

tous les objets dans le référentiel et tout autre magasin d'objets (pas seulement les objets accessibles)

(soulignement le mien).

Par défaut, cela donne le type d'objet et sa taille avec chaque hachage, mais vous pouvez facilement supprimer ces informations, par exemple avec

git cat-file --batch-check --batch-all-objects | cut -d' ' -f1

ou en donnant un format personnalisé à --batch-check.

22
Erki der Loony

Il s'agit d'une interprétation plus correcte, plus simple et plus rapide du script à partir des réponses par Mark et par willkill .

  • Il utilise rev-parse --git-path pour trouver le répertoire objects même dans une configuration de référentiel Git plus complexe (par exemple dans une situation à plusieurs postes de travail ou autre).

  • Il évite toute utilisation inutile de find, grep, Perl, sed.

  • Si fonctionne correctement même si vous n'avez pas d'objets en vrac ou pas de packs (ou ni l'un ni l'autre… si vous êtes enclin à l'exécuter sur un nouveau référentiel).

  • Il faut cependant un Bash de ce millénaire ???? (2.02 ou plus récent, en particulier, pour le bit extglob).

Partagez et profitez.

#!/bin/bash
set -e
shopt -s nullglob extglob

cd "`git rev-parse --git-path objects`"

# packed objects
for p in pack/pack-*([0-9a-f]).idx ; do
    git show-index < $p | cut -f 2 -d ' '
done

# loose objects
for o in [0-9a-f][0-9a-f]/*([0-9a-f]) ; do
    echo ${o/\/}
done
8

Je ne connais pas de meilleure manière évidente que de simplement regarder tous les fichiers d'objets en vrac et les indices de tous les fichiers de pack. Le format du référentiel git est très stable, et avec cette méthode, vous n'avez pas besoin d'avoir exactement les bonnes options pour git fsck, qui est classé comme porcelaine. Je pense que cette méthode est également plus rapide. Le script suivant montre tous les objets d'un référentiel:

#!/bin/sh

set -e

cd "$(git rev-parse --show-cdup)"

# Find all the objects that are in packs:

for p in .git/objects/pack/pack-*.idx
do
    git show-index < $p | cut -f 2 -d ' '
done

# And now find all loose objects:

find .git/objects/ | egrep '[0-9a-f]{38}' | \
  sed -r 's,^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}),\1\2,'

(Ma version originale de ce script était basée sur ce script utile pour trouver les plus gros objets dans vos fichiers pack , mais je suis passé à l'utilisation de git show-index, comme suggéré dans votre question.)

J'ai transformé ce script en n GitHub Gist .

6
Mark Longair

La commande git cat-file --batch-check --batch-all-objects, Suggérée dans Erki Der Loony 's answer , peut être exécutée plus vite avec le nouveau Git 2.19 (Q3 2018) option --unordered.

L'API pour parcourir tous les objets appris à lister éventuellement les objets dans l'ordre dans lequel ils apparaissent dans les fichiers pack , ce qui aide la localité d'accès si l'appelant accède à ces objets tout en que les objets sont énumérés.

Voir commit 0889aae , commit 79ed0a5 , commit 54d2f0d , commit ced9fff (14 août 2018), et commit 0750bb5 , commit b1adb38 , commit aa2f5ef , commit 736eb88 , commit 8b36155 , commit a7ff6f5 , commit 202e7f1 (10 août 2018) par Jeff King (peff)(Fusionné par Junio ​​C Hamano - gitster - in commit 0c54cda , 20 août 2018)

cat-file: Prend en charge la sortie "unordered" pour --batch-all-objects

Si vous allez accéder au contenu de chaque objet dans un packfile, il est généralement beaucoup plus efficace de le faire dans l'ordre du pack, plutôt que dans le hachage . Cela augmente la localité d'accès dans le packfile, qui à son tour est plus convivial pour le cache de base delta, car le packfile place les deltas associés les uns à côté des autres. En revanche, l'ordre de hachage est effectivement aléatoire, car sha1 n'a aucune relation discernable avec le contenu.

Ce patch introduit une option "--unordered" Dans cat-file Qui itère sur les packs dans l'ordre des packs sous le capot. Vous pouvez voir les résultats lors du vidage de tout le contenu du fichier:

$ time ./git cat-file --batch-all-objects --buffer --batch | wc -c
  6883195596

real 0m44.491s
user 0m42.902s
sys  0m5.230s

$ time ./git cat-file --unordered \
                    --batch-all-objects --buffer --batch | wc -c
  6883195596

real 0m6.075s
user 0m4.774s
sys  0m3.548s

Même sortie, ordre différent, beaucoup plus rapide. La même accélération s'applique même si vous finissez par accéder au contenu de l'objet dans un processus différent, comme:

git cat-file --batch-all-objects --buffer --batch-check |
grep blob |
git cat-file --batch='%(objectname) %(rest)' |
wc -c

L'ajout de "--unordered" À la première commande fait passer le temps d'exécution dans git.git De 24 secondes à 3,5 secondes.

Note latérale: il existe actuellement d'autres accélérations pour tout faire en cours. Étant donné que nous générons le contenu de l'objet pendant l'itération réelle du pack, nous savons où trouver l'objet et pouvons ignorer la recherche supplémentaire effectuée par oid_object_info(). Ce correctif s'arrête avant cette optimisation car l'API sous-jacente n'est pas prête pour que nous puissions faire ce genre de demandes directes.

Donc, si --unordered Est tellement mieux, pourquoi ne pas en faire la valeur par défaut? Deux raisons:

  1. Nous avons promis dans la documentation que --batch-all-objects Sort dans un ordre de hachage. Puisque cat-file Est de la plomberie, les gens peuvent se fier à cette valeur par défaut, et nous ne pouvons pas la changer.

  2. C'est en fait plus lent dans certains cas. Nous devons calculer le pack revindex pour marcher dans l'ordre des packs. Et notre étape de déduplication utilise un oidset, plutôt qu'un tri et une déduplication, qui peuvent finir par être plus chers.

Si nous accédons simplement au type et à la taille de chaque objet, par exemple, comme:

git cat-file --batch-all-objects --buffer --batch-check

mes meilleurs timings de cache chaud vont de 900 ms à 1 100 ms en utilisant --unordered. Bien qu'il soit possible dans un cache froid ou sous pression de mémoire que nous pourrions faire mieux, car nous aurions une meilleure localité dans le packfile.

Et une dernière question: pourquoi est-ce "--unordered" Et non "--pack-order"? La réponse est à nouveau double:

  1. "Ordre d'emballage" n'est pas une chose bien définie à travers l'ensemble des objets. Nous frappons des objets en vrac, ainsi que des objets dans plusieurs packs, et le seul ordre que nous promettons est dans un seul pack. Le reste est apparemment aléatoire.

  2. Le point ici est l'optimisation. Nous ne voulons donc pas promettre de commande particulière, mais seulement pour dire que nous choisirons une commande susceptible d'être efficace pour accéder au contenu de l'objet. Cela laisse la porte ouverte à d'autres modifications à l'avenir sans avoir à ajouter une autre option de compatibilité


Il est encore plus rapide dans Git 2.20 (Q4 2018) avec:

Voir commit 8c84ae6 , commit 8b2f8cb , commit 9249ca2 , commit 22a1646 , commit bf73282 (04 octobre 2018) par René Scharfe (rscharfe) .
(Fusionné par Junio ​​C Hamano - gitster - in commit 82d0a8c , 19 octobre 2018)

oidset: utilisez khash

Réimplémentez oidset en utilisant khash.h afin de réduire son empreinte mémoire et de la rendre plus rapide.

Performance d'une commande qui vérifie principalement les objets en double à l'aide d'un oidset, avec master et Clang 6.0.1:

$ cmd="./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'"

$ /usr/bin/time $cmd >/dev/null
0.22user 0.03system 0:00.25elapsed 99%CPU (0avgtext+0avgdata 48484maxresident)k
0inputs+0outputs (0major+11204minor)pagefaults 0swaps

$ hyperfine "$cmd"
Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'

Time (mean ± σ):     250.0 ms ±   6.0 ms    [User: 225.9 ms, System: 23.6 ms]

Range (min … max):   242.0 ms … 261.1 ms

Et avec ce patch:

$ /usr/bin/time $cmd >/dev/null
0.14user 0.00system 0:00.15elapsed 100%CPU (0avgtext+0avgdata 41396maxresident)k
0inputs+0outputs (0major+8318minor)pagefaults 0swaps

$ hyperfine "$cmd"
Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'

Time (mean ± σ):     151.9 ms ±   4.9 ms    [User: 130.5 ms, System: 21.2 ms]

Range (min … max):   148.2 ms … 170.4 ms

Git 2.21 (Q1 2019) optimise davantage le chemin de code pour écrire le graphe de validation, en suivant le modèle habituel de visite des objets dans l'ordre dans le pack.

Voir commit d7574c9 (19 janvier 2019) par Ævar Arnfjörð Bjarmason (avar) .
(Fusionné par Junio ​​C Hamano - gitster - in commit 04d67b6 , 05 février 2019)

Optimisez légèrement l'étape "écriture du graphe de validation" en utilisant FOR_EACH_OBJECT_PACK_ORDER Avec for_each_object_in_pack().
Derrick Stolee a fait ses propres tests sur Windows montrant une amélioration de 2% avec un haut degré de précision.


Git 2.23 (Q3 2019) améliore " git rev-list --objects " qui a appris avec l'option "--no-object-names" Pour écraser le chemin vers l'objet qui est utilisé comme indice de regroupement pour le pack -objets.

Voir commit 42357b4 (19 juin 2019) par Emily Shaffer (nasamuffin) .
(Fusionné par Junio ​​C Hamano - gitster - in commit f4f7e75 , 09 juil.2019)

rev-list: Apprenez à --no-object-names À activer la tuyauterie

Permet une analyse plus facile par cat-file En donnant à rev-list une option pour imprimer uniquement le OID d'un objet non-commit sans aucune information supplémentaire).
Il s'agit d'une cale à court terme; plus tard, rev-list devrait apprendre à imprimer les types d'objets qu'il trouve dans un format similaire à celui de cat-file.

Avant cette validation, la sortie de rev-list Devait être massée avant d'être redirigée vers cat-file, comme ceci:

git rev-list --objects HEAD | cut -f 1 -d ' ' |
    git cat-file --batch-check

Cela était particulièrement inattendu lorsqu'il s'agissait d'arbres racine, car un espace invisible existe à la fin de l'OID:

git rev-list --objects --filter=tree:1 --max-count=1 HEAD |
    xargs -I% echo "AA%AA"

Maintenant, il peut être canalisé directement, comme dans le cas de test ajouté:

git rev-list --objects --no-object-names HEAD | git cat-file --batch-check

Voilà donc la différence entre:

vonc@vonvb:~/gits/src/git$ git rev-list --objects HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44 
55d368920b2bba16689cb6d4aef2a09e8cfac8ef Documentation
9903384d43ab88f5a124bc667f8d6d3a8bce7dff Documentation/RelNotes
a63204ffe8a040479654c3e44db6c170feca2a58 Documentation/RelNotes/2.23.0.txt

Et, avec --no-object-name:

vonc@vonvb:~/gits/src/git$ git rev-list --objects --no-object-names HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44
55d368920b2bba16689cb6d4aef2a09e8cfac8ef
9903384d43ab88f5a124bc667f8d6d3a8bce7dff
a63204ffe8a040479654c3e44db6c170feca2a58
5
VonC

Une autre option utile consiste à utiliser git verify-pack -v <packfile>

verify-pack -v répertorie tous les objets de la base de données avec leur type d'objet.

2
nimrodm