¿Cómo desempacar packed-refs?

He clonado un proyecto de github con git clone –mirror . Eso me dejó con un repository con un file packed- refs , un .pack y un file .idx . Para fines de desarrollo, quiero ver los objects sueltos, por lo que desempaqué los objects con git unpack-objects <<pack file> que funcionó bien (descomprimí el file del package en un nuevo repository si te lo estás planteando). Lo único es que los refs / heads / todavía están vacíos, todos los refs solo están en packed-ref pero los necesito en refs / heads / . No pude encontrar un command que extrajera o descomprimiera esas references y de alguna manera no puedo creer que tendría que hacerlo a mano (o a través de tuberías).

Entonces en realidad tengo dos preguntas:

  1. ¿Hay alguna manera fácil de "restaurar" refs de packed-refs ?
  2. Si no, ¿por qué no está allí? Si hay un command para desempaquetar objects, ¿cuál es el razonamiento detrás de no proporcionar lo mismo para los refs (no olvide que hay incluso un command git pack-refs …)

Gracias por cualquier consejo e idea.

La respuesta corta es "no", no hay una "manera fácil" de desempaquetar a los árbitros de la manera en que lo pides.

La respuesta ligeramente más larga es que cada reference es solo un file de text de 41 bytes (SHA1 de 40 bytes en hexadecimal + nueva línea) en una ruta específica, por lo que la versión "difícil" solo requiere algo como esto en su ~/.gitconfig :

 [alias] unpack-refs = "!bash -c 'IFS=$''\\n''; for f in $(git show-ref --heads); do /bin/echo ''Writing '' $(echo $f | cut -c42-); echo $(echo $f | cut -c1-40) > \"${GIT_DIR:-.git}/$(echo $f | cut -c42-)\"; done'" 

Tomó un poco de truco para descubrir cómo hacer que funcione correctamente, ¡pero ya está! Ahora tienes 'git unpack-refs' y hace lo que esperas, y como beneficio adicional, incluso funciona con $ GIT_DIR si eso está establecido (de lo contrario se supone que estás en la raíz del tree de git). Si no ha leído los alias de git, https://git.wiki.kernel.org/index.php/Aliases es una gran reference e incluso incluye un ejemplo de extensión 'git alias' que puede usar para extender sus propios alias .

La razón por la que existen los refs empaquetados es para acelerar el acceso en un repository con millones de refs: es más fácil mirar un único file con muchas líneas que ingresar al sistema de files una vez por cada ref. Cualquier cosa en git que necesite saber sobre refs pasa por un código que puede leer tanto el directory refs como el file refs empaquetado. Desempacarlo vencería su propósito. Si desea acceder a los refs, use los commands de plomería (por ejemplo, show-ref, for-each-ref, update-ref …). Realmente no puedo pensar en ningún tipo de acceso que sería más rápido y más fácil con la estructura de directorys que con los commands de plomería (especialmente con for-each-ref disponible).

Y sí, los objects empaquetados son (como refs empaquetados) creados para un mejor performance, pero hay una gran diferencia. Un file refs empaquetado es solo un grupo de líneas independientes. Puede, esencialmente de forma gratuita, agregar o quitar de él. No hay necesidad de descomprimirlo para modificarlo. Los objects empaquetados, por otro lado, están comprimidos en delta, por lo que los objects internos dependen uno del otro. Reducen en gran medida el uso del disco, y los objects pueden leerse a un costo razonable, pero intentar modificar el set de objects en el package es mucho más caro que modificar objects sueltos, por lo que solo se realiza periódicamente mediante git repack (llamado por git gc ), aunque no creo que git repack realmente desempackage los objects, simplemente los lee del file de package, los empaqueta con los sueltos y crea un nuevo package.

Sin embargo, cuando un package se transfiere desde un control remoto, se desempaqueta en el lado local. Veo una llamada a un método de desempaquetado en la fuente de git receive-pack , y la página pack-objects manual de pack-objects dice:

El command git unpack-objects puede leer el file empaquetado y expandir los objects contenidos en el package en formatting de "un file de un object"; esto normalmente lo hacen los commands de extracción inteligente cuando un package se crea sobre la marcha para un transporte de networking eficiente por parte de sus compañeros.

Otra respuesta a tu pregunta 1:

Supongo que ya usaste un bucle como este para usar git unpack-objects:

  mkdir CLONE mv .git/objects/pack/* CLONE/ for pack in CLONE/*.pack; do git unpack-objects < $pack done rm -rf CLONE/ 

que desempaqueta todos los objects, pero deja las cabezas de twigs empaquetadas en el file .git / packed-refs

Gracias a la respuesta de Clee, que he reutilizado aquí, descubrí que se necesitarán los siguientes commands para descomprimir las cabezas de las twigs y limpiar:

 ( IFS=$'\n'; # set the input field separator to new line for f in $(git show-ref --heads); do ref_hash="$(echo $f | cut -c1-40)" ref_label="$(echo $f | cut -c42-)" echo " unpack: $ref_hash $ref_label" echo "$ref_hash" > ".git/$ref_label"; sed -i "s~^${ref_hash} ${ref_label}\$~~" .git/packed-refs sed -i '/^$/d' .git/packed-refs done rm .git/info/refs rm .git/objects/info/packs ) 

Tenga en count la diferencia con la respuesta de Clee:

A) los refs empaquetados se eliminan del file .git / packed-refs, y

B) los files .git / info / refs y .git / objects / info / packs se eliminan.

Admito que podría no ser una buena idea eliminar files así en la carpeta .git, sin embargo, esto es lo que necesitaba hacer para realizar un desempaquetado limpio.

La pregunta 2 aún no ha sido respondida.