tipos - git ver archivos modificados
git filter-branch condujo a un historial desconectado: ¿cómo deshacerse de los viejos commits? (2)
El escenario es el siguiente:
Tengo un gran repositorio CVS que quiero convertir a 14 repositorios git distintos. La parte cvs2git
del proceso está bien y lleva a un gran repositorio repo.git.
Para cada uno de los 14 git repo, clono el repositorio principal y ejecuto el siguiente comando:
git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --subdirectory-filter "sub/directory" -- --all
Sin embargo, antes de este comando, tengo que realizar otro comando git filter-branch
para algunos repositorios git porque tengo que reescribir los commits para mover un archivo de un directorio a otro. El --tree-filter
es la opción que uso. Aquí hay un ejemplo de la línea de comando ejecutada:
script_tree_filter="if test -f rep/to/my/file && test -d another/rep ; then echo Moving my file ; mv rep/to/my/file another/rep; fi"
git filter-branch -d /tmp/rep --tag-name-filter cat --prune-empty --tree-filter ''$script_tree_filter'' -- --all
Al final del proceso (14500 confirmaciones: ¡demora alrededor de 1 hora!) Limpio los refs y uso git gc
:
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --prune=now
Al final, obtengo un repositorio con un tamaño de 1.2Go (que obviamente sigue siendo demasiado grande), y al observar los commits, puedo ver que muchos de los antiguos aún están presentes. Se refieren a archivos y directorios que ya no deberían estar aquí después del --subdirectory-filter
.
En la historia de los commits, hay una discontinuidad entre los commits no deseados y los buenos como se ve en gitk --all
:
Estoy bastante seguro de que esos commits todavía están presentes debido a las etiquetas en algunos de ellos. Si este es el caso, ¿es posible eliminar esas etiquetas sin eliminar la de las confirmaciones correctas?
Si las etiquetas no son la razón, ¿alguna idea?
Para obtener más información, el contenido del directorio refs
(en el repositorio git obtenido por el subdirectorio-filtro) está vacío:
$ ls -R refs/
refs/:
heads original tags
refs/heads:
refs/original:
refs
refs/original/refs:
heads tags
refs/original/refs/heads:
refs/original/refs/tags:
refs/tags:
Descubrí que las ramas y las etiquetas se enumeran en el archivo packed-refs
en el repositorio de git:
d0c675d8f198ce08bb68f368b6ca83b5fea70a2b refs/tags/v03-rev-04
95c3f91a4e92e9bd11573ff4bb8ed4b61448d8f7 refs/tags/v03-rev-05
Hay 817 etiquetas y 219 ramas enumeradas en el archivo.
Apuesto a que te están golpeando con esto:
Diferencias entre CVS y los modelos de git branch / tag: CVS permite crear una rama o etiqueta a partir de combinaciones arbitrarias de revisiones de fuentes de múltiples ramas de origen. Incluso permite que las revisiones de archivos que nunca fueron contemporáneas se agreguen a una sola rama / etiqueta. Git, por otro lado, solo permite que el árbol fuente completo, tal como existió en algún momento de la historia, se ramifique o marque como una unidad. Además, la ascendencia de una revisión de git tiene implicaciones sobre el contenido de esa revisión. Esta diferencia significa que es fundamentalmente imposible representar un historial de CVS arbitrario en un repositorio de git 100% fielmente. cvs2git utiliza las siguientes soluciones alternativas:
cvs2git intenta crear una rama a partir de una única fuente, pero si no puede averiguar cómo hacerlo, crea la rama utilizando una "fusión" desde múltiples ramas de origen. En situaciones patológicas, el número de fuentes de fusión para una sucursal puede ser arbitrariamente grande. El historial resultante implica que cada vez que se agregaba un archivo a una rama, toda la rama fuente se fusionaba en la rama de destino, lo que es claramente incorrecto. (La alternativa, omitir la fusión, descartaría la información de que parte del contenido se movió de una rama a otra).
Si cvs2git no puede determinar que una etiqueta CVS se puede crear a partir de una única revisión, entonces crea una rama de reparación de etiqueta llamada TAG.FIXUP, luego etiqueta esta rama. (Esta es una solución necesaria para el hecho de que git solo permite etiquetar las revisiones existentes). La rama TAG.FIXUP se crea como una combinación entre todas las ramas que contienen revisiones de archivos incluidas en la etiqueta, lo que implica la misma compensación descrita arriba para las ramas. La rama TAG.FIXUP se borra al final de la conversión, pero (debido a una limitación técnica del formato de archivo de importación rápida de git) no se elimina. Hay algunas situaciones en las que se puede crear una etiqueta a partir de una única revisión, pero cvs2git no se da cuenta y crea una rama de corrección de etiqueta superflua. Es posible eliminar ramas de corrección de etiqueta superfluas después de la conversión ejecutando el script contrib / git-move-refs.py dentro del repositorio de git resultante.
No hay comprobaciones de que los nombres de rama y etiqueta de CVS sean nombres legales de git. Probablemente haya otras restricciones de git que también deberían verificarse. ver cvs2git
¿Está mostrando el directorio refs de los nuevos directorios o del repo grande después de la conversión? Puede eliminar las etiquetas en su repositorio grande de exportación antes de filtrar y dividir el repositorio grande.
Puede eliminar etiquetas en el repositorio grande simplemente borrando el archivo en el directorio; es solo una referencia a un SHA.
Pude resolver mi problema cambiando la forma en que usé cvs2git
: en lugar de convertir toda la base de CVS y luego usar el comando subdirectory-filter
, convertí cada uno de los submódulos que quería. En mi caso, esto llevó a lanzar 18 comandos cvs2git
diferentes:
antes de
cvs2git --blobfile=blob --dump=dump /path/to/cvs/base
# Module 1
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module1" -- --all
# Module 2
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter "path/to/module2" -- --all
Ahora
# Module 1
cvs2git --blobfile=blob_module1 --dump=dump_module1 /path/to/cvs/base/path/to/module1
# Module 2
cvs2git --blobfile=blob_module2 --dump=dump_module2 /path/to/cvs/base/path/to/module2
Cada repositorio tiene ahora una historia perfecta.
¿Por qué el método anterior no funcionó? Supongo que cvs2git
se confundió con todos los submódulos (algunos de ellos cambiaron su nombre de directorio durante su historial).
@Michael @CharlesB Gracias por tomarse su tiempo para responder y ayudarme.