Al intentar reflejar un repositorio en un servidor remoto, el servidor rechaza el objeto de árbol 4e8f805dd45088219b5662bd3d434eb4c5428ec0. Este no es un árbol de nivel superior, por cierto, sino un subdirectorio.
¿Cómo puedo averiguar qué confirmaciones hacen referencia indirecta a ese objeto de árbol para poder evitar enviar las referencias que se vinculan a esas confirmaciones para que el resto de mi repositorio se envíe correctamente?
Torek
Como notó, solo necesita encontrar las confirmaciones con el deseado tree
. si pudiera ser un nivel superior árbol, necesitaría una prueba adicional, pero como no lo es, no la necesita.
Usted quiere:
- para algún conjunto de confirmaciones (todas aquellas accesibles desde un nombre de rama dado, por ejemplo)
- si esa confirmación tiene, como subárbol, el hash del árbol de destino: imprima la ID de la confirmación
lo cual es trivial con dos comandos de “plomería” de Git más grep
.
Aquí hay una versión ligeramente actualizada de mi script original (actualizado para tomar argumentos y predeterminado a --all
como en la edición de badp):
#! /bin/sh
#
case $# in
0) echo "usage: git-searchfor <object-id> [<starting commit>...]" 1>&2; exit 1;;
esac
searchfor=$(git rev-parse --verify "$1") || exit 1
searchfor=$(git rev-parse --verify "$searchfor"^{tree}) || exit 1
shift
git log ${@-"--all"} --pretty='format:%H' |
while read commithash; do
if git ls-tree -d -r --full-tree $commithash | grep $searchfor; then
echo " -- found at $commithash"
fi
done
Para verificar los árboles de nivel superior, haría git cat-file -p $commithash
también y ver si tiene el hash en él.
Tenga en cuenta que este mismo código encontrará blobs (suponiendo que elimine el -d
opción de git ls-tree
). Sin embargo, ningún árbol puede tener el ID de un blob, o viceversa. los grep
imprimirá la línea coincidente para que veas, por ejemplo:
040000 tree a3a6276bba360af74985afa8d79cfb4dfc33e337 perl/Git/SVN/Memoize
-- found at 3ab228137f980ff72dbdf5064a877d07bec76df9
Para limpiar esto para uso general, es posible que desee utilizar git cat-file -t
en la búsqueda de blob-or-tree para obtener su tipo.
Como jthill señala en un comentario, git diff-tree
ahora tiene un --find-object
opción. Esto se introdujo en Git 2.17 (lanzado en 2018, mucho después de la pregunta original aquí). los git log
comando también tiene esto, pero por lo general estamos más interesados en qué compromiso específico se agregó un archivo o árbol. Al eliminar la línea adicional que intenta forzar la searchfor
hash ID para ser un árbol, podemos obtener una secuencia de comandos mucho más rápida que encuentre cada aparición de cualquier árbol o objeto blob (aunque debe tener cuidado de especificar la ID hash correcta o usar el ^{tree}
adjunte su sufijo si va a proporcionar un ID de hash de confirmación). Luego simplemente ejecutamos:
git log --all --find-object=$searchfor
o, como en el comentario a continuación:
git rev-list --all | git diff-tree --stdin --find-object=$searchfor
para encontrar lo que estamos buscando. (Agregar ${2-"--all"}
si/como se desee.)
-
¡Gracias! Esto debería funcionar, aunque como no sé qué rama/etiqueta tiene el árbol defectuoso, tendría que ejecutar todo en un bucle sobre cada una de mis varias miles de ramas (es un gran repositorio con muchos usuarios) . Así que tendré que diseñar alguna forma de obtener una lista de cada confirmación en el repositorio en las ramas y eliminar los duplicados primero. Pero este es un gran comienzo.
– Andrew Arnott
12 de diciembre de 2016 a las 0:33
-
Parece que
git rev-list
devuelve un conjunto de confirmaciones para cualquier número de referencias. y se necesita--stdin
como parámetro. Entonces puedo hacergit branch -r | git rev-list --stdin
y, de lo contrario, siga usando su script. 🙂 Exceptogit branch
agrega espacios en blanco delante de cada nombre de rama, lo quegit rev-list
no le gusta, así que escribí en un archivo, lo limpié y luego lo introduje en su secuencia de comandos. Ahora está muy ocupado buscando.– Andrew Arnott
12 de diciembre de 2016 a las 0:42
-
Incluso pude cambiar
origin/master
a^origin/master
para reducir en gran medida la cantidad de confirmaciones, ya que sé que el árbol en cuestión no está en ninguna parte de la rama principal.– Andrew Arnott
12 de diciembre de 2016 a las 0:43
-
git rev-list
toma el mismo argumentos comogit log
. De hecho, ¡son básicamente el mismo comando! Se construyen a partir de un archivo fuente que solo cambia la configuración predeterminada cuando se ejecuta comogit log
contragit rev-list
. Sin embargo, Rev-list está diseñado para usarse en scripts, mientras que log está diseñado para ser utilizado por humanos. En todo casoA..B
“medio”B ^A
asi queorigin/master..master
ymaster ^origin/master
son exactamente lo mismo aquí. En este caso puedes usargit rev-list --branches ^origin/master
(o tal vez--branches --tags
).– torek
12 de diciembre de 2016 a las 2:50
-
Entonces, ¡funcionó! Descubrí que el script sutilmente solo encontraría árboles que son subdirectorios del actual (en lugar de comenzar en la raíz). Lo arreglé, pero tardó tanto en completarse, y tenía una idea bastante buena de qué directorio representaba el árbol, así que aproveché eso como una optimización. Ahora tengo varias confirmaciones con las que trabajar. 🙂
– Andrew Arnott
12 de diciembre de 2016 a las 3:57
Variación de gran respuesta por torek en caso de que quiera acelerar las cosas a través de GNU paralelo:
#!/bin/bash
searchfor="$1"
startpoints="${2-HEAD}"
git rev-list "$startpoints" |
parallel "if git ls-tree -d -r --full-tree '{}' | grep '$searchfor'; then echo ' -- found at {}'; fi"
He considerado eliminar el objeto del árbol y luego ejecutar
git fsck
con la esperanza de que eliminaría todas las referencias a él como parte de la recuperación. Pero tampoco sé cómo eliminar un objeto de un archivo de paquete.– Andrew Arnott
11 de diciembre de 2016 a las 15:58
¿Qué tal si solucionamos el problema? Use “git bisect” para encontrar la confirmación que introdujo la referencia del árbol defectuoso, y luego puede usar git ls-tree para encontrar el árbol defectuoso.
–Raymond Chen
11 de diciembre de 2016 a las 18:03
@RaymondChen Eso podría no funcionar. Además de tomar tanto tiempo (la bisección es increíble, pero no tanto en un árbol tan grande), puede fallar porque el árbol en sí mismo puede fallar al realizar el pago en el compromiso relevante. Además, necesito un compromiso de muestra “bueno” y “malo” para bisect para comenzar, y no sé qué compromiso es malo.
– Andrew Arnott
12 de diciembre de 2016 a las 0:16