¿Es posible que git-merge ignore las diferencias de final de línea?

150

¿Es posible git mergeignorar las diferencias de final de línea?

Tal vez estoy haciendo la pregunta equivocada ... pero:

Traté de usar config.crlf inputpero las cosas se pusieron un poco desordenadas y fuera de control, especialmente cuando lo apliqué después del hecho .

Por un lado, la aplicación de esta configuración después del hecho no parece afectar a los archivos comprometidos en el repositorio antes de aplicar esta opción. Otra cosa es que, de repente, todas las confirmaciones ahora dan como resultado muchos mensajes de advertencia molestos sobre la conversión de CRLF a LF.

Para ser honesto, no me importa qué final de línea se use, personalmente prefiero el estilo Unix \n, pero lo que sea. Lo único que me importa es git mergeser un poco más inteligente e ignorar las diferencias en los finales de línea.

A veces tengo dos archivos idénticos, pero git los marcaría como en conflicto (y el conflicto es el archivo completo ) simplemente porque usan un carácter de final de línea diferente.

Actualizar:

Descubrí que git diffacepta una --ignore-space-at-eolopción, ¿sería posible dejar de git mergeusar esta opción también?

Hasen
fuente
28
Oh deseo Esta línea que termina en git está totalmente rota
1800 INFORMACIÓN
Acabo de agregar un caso de prueba que ilustra que la herramienta de fusión de terceros ignorará el estilo de
EOL
Entonces, para aclarar (por lo que puedo determinar): ¿no hay forma de que git ignore los CR pero se queje de todos los demás espacios en blanco finales?
Stephen
Asegúrese de echar un vistazo a la respuesta a continuación sobregit config merge.renormalize true
qneill

Respuestas:

115

Actualización 2013:

Las versiones más recientes de git autorizan el uso de combinación con estrategia recursivey opción de estrategia ( -X):

git merge -s recursive -Xignore-space-at-eol

Pero usar " -Xignore-space-change" también es una posibilidad


jakub.g también comenta que las estrategias funcionan también con la selección de cerezas :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Esto funciona mucho mejor que ignore-all-space.


Respuesta original (mayo de 2009)

El parche para ignorar el estilo EOL se propuso en junio de 2007 , pero solo concierne git diff --ignore-space-at-eol, no git merge.

En ese momento, la pregunta ha sido formulada:

Debería --ignore-space-at-eolser una opción para git-merge?
Las fusiones son donde esta funcionalidad importa.
¿Cuáles son las semánticas de una fusión resuelta automáticamente con esas opciones vigentes? ¿Se usan solo para la detección de cambio de nombre o, por ejemplo, no marcamos conflictos con solo cambios en espacios en blanco? Y si no lo hacemos, ¿qué versión aceptamos automáticamente?

Julio C Hamano no estaba exactamente entusiasmado:

Esto ciertamente es tentador, pero sospecho que debería dejarse en rondas posteriores.
Sospecho que introduciría un concepto de dos tipos diferentes de diferencias, una para ser procesada mecánicamente (es decir, usar en combinación con "git-merge-recursive" y aplicar con "git-am"), y otra para ser inspeccionada por humanos para entender.
A menudo puede ser útil combinar la entrada para el último caso, aunque la salida de la comparación de archivos de entrada combinados puede no ser fácilmente utilizable para la aplicación mecánica.

La idea general, cuando se trata git merge, es confiar en la herramienta de combinación de terceros.

Por ejemplo, he configurado DiffMerge para que sea la herramienta para la fusión de Git, estableciendo un conjunto de reglas que permite que esa herramienta de fusión ignore eol para cierto tipo de archivos.


Configuración en Windows, con MSysGit1.6.3, ya sea para sesión DOS o Git bash, con DiffMerge o KDiff3:

  • establecer un directorio en su RUTA (aquí:) c:\HOMEWARE\cmd.
  • agregue en ese directorio el script merge.sh (contenedor para su herramienta de combinación favorita)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Declara tu contenedor de fusión para Git

Comandos de configuración de Git:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Compruebe que autoCRLF es falso

git config a nivel de sistema:

git config ---system core.autoCRLF=false
  • Pruebe que, cuando dos líneas son idénticas (pero sus caracteres de eol), DiffMerge o KDiff3 ignorarán esas líneas durante una fusión.

Script DOS (nota: el comando dos2unix viene de aquí , y se usa para simular un estilo EOL de Unix. Ese comando se ha copiado en el directorio mencionado al principio de esta respuesta):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

En este punto (presionando "volver"), se abrirán DiffMerge o KDiff3, y verá por sí mismo qué líneas se fusionan realmente y qué líneas se ignoran.

Advertencia : el archivo de resultados siempre estará en modo Windows EOL (CRLF) con DiffMerge ...
KDiff3 ofrece guardar de una forma u otra.

VonC
fuente
¡Gracias por el consejo! Meld y FileMerge en Mac también parecen ser excelentes aplicaciones.
Léo Léopold Hertz 준영
1
Para obtener información, las estrategias también funcionan con la selección de cerezas : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (esto funciona mucho mejor que ignore-all-space)
jakub.g
1
@ jakub.g buen punto! Lo he incluido en la respuesta para mayor visibilidad.
VonC
98

Estaba buscando la misma respuesta y descubrí esto

Fusionar sucursales con diferentes atributos de ingreso / salida

Si ha agregado atributos a un archivo que hace que cambie el formato del repositorio canónico para ese archivo, como agregar un filtro limpio / manchado o atributos text / eol / ident, fusionar cualquier cosa donde el atributo no esté en su lugar normalmente causaría conflictos de fusión .

Para evitar estos conflictos de fusión innecesarios, se le puede decir a git que ejecute una extracción y un registro virtuales de las tres etapas de un archivo al resolver una fusión tripartita configurando la variable de configuración merge.renormalize. Esto evita que los cambios causados ​​por la conversión de check-in provoquen conflictos de fusión espurios cuando un archivo convertido se fusiona con un archivo no convertido.

Siempre y cuando una "mancha → limpiar" produzca el mismo resultado que una "limpieza" incluso en archivos que ya están manchados, esta estrategia resolverá automáticamente todos los conflictos relacionados con el filtro. Los filtros que no actúan de esta manera pueden causar conflictos de fusión adicionales que deben resolverse manualmente.

Entonces, ejecutar este comando en cualquier repositorio hará el truco:

git config merge.renormalize true
Fabio
fuente
20
Esto merece ahora ser la respuesta predeterminada. Mucho ha cambiado desde que se hizo la pregunta por primera vez, el manejo de esto por parte de git ahora está integrado con merge.renormalize como usted dice.
Anton I. Sipos
Esto es simplemente impresionante .. salva mi día
Matthaeus
4

Lo que hice fue dejar todo como predeterminado (es decir, autocrlf = true), tocar todos los archivos (buscar. -Exec touch {} \;), dejar que git los vea como 'modificados' y confirmarlos, y listo. De lo contrario, siempre estará plagado de mensajes molestos o diferencias sorprendentes, o tendrá que desactivar todas las funciones de espacio en blanco de git.

Perderá la información de la culpa, pero es mejor hacerlo más temprano que tarde :)

Ben Hymers
fuente
4

"git merge -Xrenormalize" funciona a las mil maravillas.

Jake
fuente
0

Ahora me parece que la mejor manera es normalizar las terminaciones de línea en ambas ramas (y commit) antes de fusionarlas.

Busqué en Google "convertir crlf a lf" y encontré esto como los primeros resultados:
http://stahlforce.com/dev/index.php?tool=remcrlf

Lo descargué y usé, parece una buena herramienta.

>sfk remcr . .py

¡Sin embargo, asegúrese de especificar un directorio y un tipo de archivo (por ejemplo, .py), de lo contrario, podría intentar meterse con el contenido del .gitdirectorio!

Hasen
fuente
0

AFAICT, (no lo he probado) podría usar git diffpara comparar la rama que desea fusionar con el ancestro común y luego aplicar los resultados git apply. Ambos comandos tienen --ignore-whitespaceopciones para ignorar los errores de final de línea y espacio en blanco.

Desafortunadamente, si el parche no se aplica limpiamente, se anula toda la operación. No puede solucionar conflictos de fusión. Hay un--reject opción para dejar trozos inalcanzables en los .rejarchivos, lo que ayuda, pero no es lo mismo que tener los conflictos de fusión mostrados en un archivo.

rjmunro
fuente
-1

Despues de leer Resolver conflictos de fusión: Forzar sobrescribir todos los archivos

Finalmente resolví mi versión de este problema. Estaba tratando de obtener actualizaciones del repositorio ascendente, pero mi actual tenía problemas relacionados con CRLF y no pude fusionarme como resultado. Cabe señalar que NO HABÍA CAMBIOS LOCALES de los que tenía que preocuparme. Los siguientes pasos resolvieron mi problema:

Según las instrucciones de github sobre las horquillas de sincronización ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Mi comprensión limitada de git me dice que esto está haciendo lo que quiero: cambiar mi bifurcación (sin cambios reales no comprometidos) para obtener todos los cambios realizados en la fuente aguas arriba. Según la página de origen, este paso normalmente no debería ser obligatorio, pero el problema de CRLF lo hizo necesario.

  3. git merge upstream/master

  4. git push
propagado
fuente
1
¿Te das cuenta de que git reset --hard upstream/mastertira tu sucursal local y la señala upstream/master, haciendo git merge upstream/masterun no-op?
Christoffer Hammarström
-1

sin embargo, sugiero usar herramientas como sed para lograr las terminaciones de línea correctas y luego los archivos diff. Pasé un par de horas en diferentes proyectos con varias terminaciones de línea.

La mejor manera era:

  1. copie solo los archivos del proyecto (omita el .gitdirectorio) a otro directorio, cree el repositorio en él, luego agregue los archivos y confirme (debe estar en la rama maestra en el nuevo repositorio).
  2. copie archivos del segundo proyecto a la misma carpeta, pero otra rama por ejemplo dev( git checkout -b dev), confirme los archivos en esta rama y ejecútelos (si el primer proyecto está en el maestro): git diff master..dev --names-only para ver solo los nombres de los archivos modificados
usuario4686964
fuente