¿Reescribir el historial de git para reemplazar todos los CRLF a LF?

32

Voy a transferir un repositorio Git privado de win32 box a Ubuntu. Aunque puedo hacer una confirmación final de dos2unix, pero me gustaría reescribir todo el historial, por lo que algunas GUI de Git mostrarán log / diff correctamente. Por ejemplo, gitg insertará líneas vacías para cada CR / LF.

Xiè Jìléi
fuente

Respuestas:

25

Puede usar git filter-branchpara eso, con la --tree-filteropción y especificando --allpara la rama.

Aquí hay un ejemplo (iniciado en un directorio vacío con un archivo de texto tipo Unix:

Preparación:

$ hexdump -C testfile 
00000000  61 0d 0a 62 0d 0a 63 0d  0a                       |a..b..c..|
00000009

$ git init
Initialized empty Git repository in /home/seigneur/tmp/a/.git/

$ git add testfile && git commit -m "dos file checked in"
[master (root-commit) df4970f] dos file checked in
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 testfile

El comando:

$ git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all

Salida:

Rewrite df4970f63e3196216d5986463f239e51eebb4014 (1/1)dos2unix: converting file testfile to Unix format ...

Ref 'refs/heads/master' was rewritten

$ hexdump -C testfile 
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006

Yo fuertemente recomiendo hacer una copia de seguridad completa de antemano . Ejecutar eso desde su máquina Linux (a menos que tenga un buen shell configurado en su entorno de Windows) es probablemente más fácil.

Editar: se invirtió la conversión la primera vez.

Estera
fuente
1
Gracias, esta publicación me ayudó mucho. Tenía algunos archivos con espacios en su nombre, un pequeño cambio a la orden original, lo arregló: git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all. Banderas -zy -0decir git ls-filese xargsimprimir e interpretar nullcomo final de línea.
Ivan
Otra alternativa al comando dos2unix es confiar en el git mismo:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas
6

La respuesta de Mat ha clavado el tema en la cabeza. Desafortunadamente en Ubuntu Linux, comenzando con la versión 10.04 (Lucid Lynx), los comandos dos2unix / unix2dos ya no están disponibles y han sido reemplazados por fromdos / todos. Además, ambos conjuntos de comandos de conversión tienen varios grados de ignorancia de la existencia de archivos binarios, por lo tanto, si su repositorio contiene imágenes, fuentes, etc., estos procesos los corromperán.

Pude encontrar una solución para el problema de corrupción de archivos binarios que usa el comando 'archivo' de Linux para identificar y procesar correctamente solo archivos de texto como se muestra a continuación. El siguiente comando usa la opción --tag-name-filter para preservar las etiquetas existentes moviéndolas a los commits recién enmendados. También utiliza el indicador --force para garantizar que el comando funcionará en caso de que haya ejecutado un filtro de árbol en su repositorio anteriormente.

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs fromdos' --tag-name-filter cat -- --all
mgorovoy
fuente
3

Y sin herramientas adicionales (como 'fromdos', 'dos2unix', etc.):

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs -0 sed -i"" -e "s/"$(printf "\015")"$//"' --tag-name-filter cat -- --all

Crossplatform (OS X, FreeBSD, Linux) útil analógico 'fromdos', 'dos2unix':

sed -i'' -e 's/'"$(printf '\015')"'$//'

Quizás útil 'unix2dos':

sed -i '' -e 's|$|'"`printf '\015'`"'|' file.name

Si está absolutamente seguro de lo que está haciendo, puede usar este simple comando en línea para eliminar "/ r" de todos los archivos en el directorio actual ".":

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;
METAJIJI
fuente
1
Más bien cambie \ r \ n a \ n en lugar de eliminar \ r solamente
xdevs23
Creo que la sedinvocación correspondiente se puede reemplazar por una más corta:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k