Pregunta

¿Existe una mejor manera de obtener una lista sin formato de SHA1 para TODOS los objetos en un repositorio que hacerlo? ls .git/objects/??/\* y cat .git/objects/pack/*.idx | git show-index?

Se acerca de git rev-list --all pero eso solo enumera los objetos de confirmación a los que hace referencia .git/refs, y estoy buscando todo incluidos los objetos sin referencia creados por git-hash-object, git-mktree, etc.

¿Fue útil?

Solución

Editar: Aristóteles al corriente Una respuesta aún mejor, que debe marcarse como correcto.

Editar: El script contenía un error de sintaxis, faltando bartosa al final del grep -v línea

La respuesta de Mark funcionó para mí, después de algunas modificaciones:

  • Usó --git-dir en vez de --show-cdup para apoyar los repos desnudos
  • Error evitado cuando no hay paquetes
  • Usó perl Porque el estilo BSD de OS X Mountain Lion sed no es compatible -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:' \
;

Otros consejos

Probar

 git rev-list --objects --all

Editar Josh hizo un buen punto:

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

Enumere los objetos accesibles de los REF-Logs.

Para ver todos los objetos en comodidades inalcanzables también:

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

Poniendo todo junto, para De Verdad Obtenga todos los objetos en el formato de salida de rev-list --objects, necesitas algo como

{
    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

Para ordenar la salida de una manera ligeramente más útil (por ruta para árbol/blobs, se compromete primero) use un adicional | sort -k2 que agrupará todas las manchas (revisiones) diferentes para caminos idénticos.

No sé desde que esta opción existe pero puedes

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

Esto te da, según la página del hombre,

Todos los objetos en el repositorio y en cualquier tienda de objetos alternativo (no solo objetos accesibles)

(énfasis mío).

Por defecto, esto produce el tipo de objeto y su tamaño junto con cada hash, pero puede eliminar fácilmente esta información, por ejemplo, con

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

o dando un formato personalizado para --batch-check.

Esta es una interpretación más correcta, más simple y rápida del script de las respuestas por marca y por Willkill.

  • Usa rev-parse --git-path para encontrar el objects Directorio incluso en una configuración de repositorio GIT más compleja (por ejemplo, en una situación de múltiples trabajos o demás).

  • Evita todo el uso innecesario de find, grep, perl, sed.

  • Si funciona con gracia, incluso si no tiene objetos sueltos o ningún paquete (o ninguno de los dos ... si está inclinado a ejecutar esto en un nuevo repositorio).

  • Sin embargo, requiere una fiesta de este milenio 😊 (2.02 o más nuevo, específicamente, para el extglob un poco).

Comparte y Disfruta.

#!/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

No sé de una manera obviamente mejor que solo mirar todos los archivos de objetos sueltos y los índices de todos los archivos de paquete. El formato del repositorio git es muy estable, y con este método no tiene que confiar en tener exactamente las opciones correctas para git fsck, que se clasifica como porcelana. Creo que este método también es más rápido. El siguiente script muestra todos los objetos en un repositorio:

#!/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,'

(Mi versión original de este script se basó en Este script útil para encontrar los objetos más grandes en sus archivos de paquete, pero cambié a usar git show-index, como se sugiere en su pregunta).

He hecho este guión en un Github Gist.

El git cat-file --batch-check --batch-all-objects comando, sugerido en Erki el loco's respuesta, Puede ser hecho más rápido con la nueva opción Git 2.19 (Q3 2018) --unordered.

La API para iterar sobre todos los objetos aprendidos Opcionalmente, enumera los objetos en el orden en que aparecen en los archivos de paquete., lo que ayuda a la localidad de acceso si la persona que llama accede a estos objetos mientras se enumeran los objetos.

Ver cometer 0889aae, cometer 79ed0a5, cometer 54d2f0d, cometer ced9fff (14 de agosto de 2018), y confirmar 0750bb5, cometer b1adb38, cometer aa2f5ef, confirmar 736eb88, cometer 8b36155, cometer a7ff6f5, cometer 202e7f1 (10 de agosto de 2018) por jeff rey (peff). (Fusionado por Junio ​​C Hamano. gitster -- en confirmar 0c54cda, 20 de agosto de 2018)

cat-file:apoyo "unordered"salida para --batch-all-objects

Si va a acceder al contenido de cada objeto en un archivo de paquete, generalmente es mucho más eficiente hacerlo en orden de paquete, en lugar de en orden hash.Esto aumenta la localidad de acceso dentro del archivo de paquete, lo que a su vez es más amigable para la caché base delta, ya que el archivo de paquete coloca los deltas relacionados uno al lado del otro.Por el contrario, el orden hash es efectivamente aleatorio, ya que el sha1 no tiene discernible relación con el contenido.

Este parche introduce un "--unordered"opción de cat-file que itera sobre paquetes en orden de paquete debajo del capó.Puede ver los resultados al descargar todo el contenido del archivo:

$ 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

Misma producción, orden diferente, mucho más rápido.Se aplica la misma velocidad, incluso si termina accediendo al contenido del objeto en un proceso diferente, como:

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

Añadiendo "--unordered" al primer comando deja caer el tiempo de ejecución en git.git de 24s a 3,5s.

Nota al margen:De hecho, ahora hay más aceleraciones disponibles para hacerlo todo en el proceso.Dado que estamos generando el contenido del objeto durante la iteración real del paquete, sabemos dónde encontrar el objeto y podemos omitir la búsqueda adicional realizada por oid_object_info().Este parche no llega a esa optimización ya que la API subyacente no está lista para que podamos realizar ese tipo de solicitudes directas.

Así que si --unordered es mucho mejor, ¿por qué no convertirlo en el predeterminado?Dos razones:

  1. Hemos prometido en la documentación que --batch-all-objects salidas en orden hash.Desde cat-file es plomería, la gente puede confiar en ese valor predeterminado y no podemos cambiarlo.

  2. en realidad es Más lento para algunos casos.Tenemos que calcular el revindex del paquete para caminar en el orden del paquete.Y nuestro paso de deduplicación utiliza un oidset, en lugar de ordenar y desduplicar, lo que puede resultar más costoso.

Si solo accedemos al tipo y tamaño de cada objeto, por ejemplo, como:

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

mis tiempos de caché caliente al mejor de cinco van de 900 ms a 1100 ms usando --unordered.Aunque es posible que en un caché frío o bajo presión de memoria podamos hacerlo mejor, ya que tendríamos una mejor localidad dentro del archivo de paquete.

Y una última pregunta:¿por qué es "--unordered" y no "--pack-order"?La respuesta es nuevamente doble:

  1. El "orden del paquete" no está bien definido en todo el conjunto de objetos.Estamos golpeando objetos sueltos, así como objetos en paquetes múltiples, y el único orden que prometemos es dentro un solo paquete.El resto es aparentemente aleatorio.

  2. El punto aquí es la optimización.Por lo tanto, no queremos prometer ningún orden en particular, sino sólo decir que elegiremos un orden que probablemente sea eficiente para acceder al contenido del objeto.Eso deja la puerta abierta a más cambios en el futuro sin tener que agregar otra opción de compatibilidad.


Es incluso más rápido en Git 2.20 (cuarto trimestre de 2018) con:

Ver cometer 8c84ae6, cometer 8b2f8cb, cometer 9249ca2, cometer 22a1646, cometer bf73282 (04 de octubre de 2018) por René Scharfe (rscharfe).
(Fusionado por Junio ​​C Hamano. gitster -- en cometer 82d0a8c, 19 de octubre de 2018)

oidset:usar khash

Reimplementar oidset usando khash.h Para reducir su huella de memoria y hacerlo más rápido.

Rendimiento de un comando que verifica principalmente objetos duplicados utilizando un set de OID, con master y Sonido metálico 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

Y con este parche:

$ /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) optimiza aún más el codepath para escribir commit-graph, siguiendo el patrón habitual de visitar los objetos en el orden del paquete.

Ver cometer d7574c9 (19 de enero de 2019) por Ævar Arnfjörð Bjarmason (avar).
(Fusionado por Junio ​​C Hamano. gitster -- en cometer 04d67b6, 05 de febrero de 2019)

Optimice ligeramente el paso de "escritura de gráfico de confirmación" utilizando FOR_EACH_OBJECT_PACK_ORDER con for_each_object_in_pack().
Derrick Stolee lo hizo sus propias pruebas en Windows mostrando un 2% mejora con un alto grado de precisión.


Git 2.23 (tercer trimestre de 2019) mejora "git rev-list --objects" que aprendió con "--no-object-names"Opción para silenciar la ruta al objeto que se utiliza como sugerencia de agrupación para objetos empaquetados.

Ver cometer 42357b4 (19 de junio de 2019) por Emily Shaffer (nasamuffin).
(Fusionado por Junio ​​C Hamano. gitster -- en cometer f4f7e75, 09 de julio de 2019)

rev-list:enseñar --no-object-names para habilitar la tubería

Permitir un análisis más fácil mediante cat-file dando a rev-list una opción para imprimir solo el OID de un objeto no comprometido, sin ninguna información adicional.
Esta es una corrección a corto plazo;mas tarde, rev-list debe enseñarse cómo imprimir los tipos de objetos que encuentra en un formato similar a cat-file's.

Antes de este compromiso, la salida de rev-list Necesitaba ser masajeado antes de ser encendido para el archivo de gato, como así:

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

Esto fue especialmente inesperado cuando se trata de árboles raíz, ya que existe un espacio blanco invisible al final del OID:

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

Ahora, se puede canalizar directamente, como en el caso de prueba agregado:

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

Entonces esa es la diferencia 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

Y con --no-object-name:

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

Otra opción útil es usar git verify-pack -v <packfile>

verify-pack -v Enumera todos los objetos en la base de datos junto con su tipo de objeto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top