git-diff para ignorar ^ M


474

En un proyecto donde algunos de los archivos contienen ^ M como separadores de nueva línea. Aparentemente, diferenciar estos archivos es imposible, ya que git-diff lo ve como todo el archivo es solo una línea.

¿Cómo difiere uno con la versión anterior?

¿Hay una opción como "tratar ^ M como nueva línea al diferenciar"?

prompt> git-diff "HEAD^" -- MyFile.as 
diff --git a/myproject/MyFile.as b/myproject/MyFile.as
index be78321..a393ba3 100644
--- a/myproject/MyFile.cpp
+++ b/myproject/MyFile.cpp
@@ -1 +1 @@
-<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
+<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
prompt>

ACTUALIZAR:

ahora he escrito un script Ruby que revisa las últimas 10 revisiones y convierte CR a LF.

require 'fileutils'

if ARGV.size != 3
  puts "a git-path must be provided"
  puts "a filename must be provided"
  puts "a result-dir must be provided"
  puts "example:"
  puts "ruby gitcrdiff.rb project/dir1/dir2/dir3/ SomeFile.cpp tmp_somefile"
  exit(1)
end

gitpath = ARGV[0]
filename = ARGV[1]
resultdir = ARGV[2]

unless FileTest.exist?(".git")
  puts "this command must be run in the same dir as where .git resides"
  exit(1)
end

if FileTest.exist?(resultdir)
  puts "the result dir must not exist"
  exit(1)
end
FileUtils.mkdir(resultdir)

10.times do |i|
  revision = "^" * i
  cmd = "git show HEAD#{revision}:#{gitpath}#{filename} | tr '\\r' '\\n' > #{resultdir}/#{filename}_rev#{i}"
  puts cmd 
  system cmd
end

77
es posible que haya querido git diff -b- Mostré esto en stackoverflow.com/a/46265081/58794
Jason Pyeron

66
Con Git 2.16 (Q1 2018), tendrás git diff --ignore-cr-at-eol. Vea mi respuesta a continuación .
VonC

77
@JasonPyeron y para futuros Googlers: tuve que buscar eso git diff -bes idéntico a git diff --ignore-space-change.
Gogowitsch

Respuestas:


392

GitHub sugiere que debe asegurarse de usar solo \ n como un carácter de nueva línea en repositorios manejados por git. Hay una opción para convertir automáticamente:

$ git config --global core.autocrlf true

Por supuesto, se dice que esto convierte crlf a lf, mientras que desea convertir cr a lf. Espero que esto todavía funcione ...

Y luego convierta sus archivos:

# Remove everything from the index
$ git rm --cached -r .

# Re-add all the deleted files to the index
# You should get lots of messages like: "warning: CRLF will be replaced by LF in <file>."
$ git diff --cached --name-only -z | xargs -0 git add

# Commit
$ git commit -m "Fix CRLF"

core.autocrlf se describe en la página del manual .


1
No, por supuesto que no, una vez que la configuración esté allí, se convertirá silenciosamente al confirmar. Si todo funciona de la manera que creo, eso es ...
nes1983

1
El problema es que ya tengo algunos archivos en el repositorio que tienen terminaciones CRLF y otros que no. Sospecho que Adobe Flash agrega CRLF aunque estoy usando la versión para Mac. Necesito comparar con revisiones anteriores de estos archivos. La conversión de terminaciones de línea a partir de ahora no resuelve el problema con revisiones anteriores: - /
neoneye

65
No estás trabajando con archivos CRLF aquí, al menos no en el ejemplo que publicaste. Ese es un archivo mac de estilo antiguo (solo usa \ r para EOL). Es por eso que la diferencia se muestra en una línea. Un archivo que usa dos EOL mostraría cada línea de forma distinta con un ^ M final, que podría decir que puede manejar a través de git config core.whitespace cr-at-eol.
jamessan

12
Estoy intentando esto, pero sigo obteniendo en warning: LF will be replaced by CRLFlugar de warning: CRLF will be replaced by LF, y estoy en Linux. ¿Alguna idea de por qué? ¡Quiero que todo termine con LF, no con CRLF!
trusktr

55
@trusktr, me pasó lo mismo. En Linux, con CRLF accidental, use git config --global core.autocrlf input, siga los pasos de esta respuesta (rm, add, commit), y obtendrá warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Elimine los archivos (porque tienen el CRLF original e incorrecto) y vuelva a pagarlos desde el último compromiso "Fix CRLF".
jmmut

370

Desarrollando en Windows, me encontré con este problema cuando lo uso git tfs. Lo resolví de esta manera:

git config --global core.whitespace cr-at-eol

Básicamente, esto le dice a Git que un CR de fin de línea no es un error. Como resultado, esos molestos ^Mpersonajes ya no aparecen al final de las líneas de git diff, git show, etc.

Parece dejar otras configuraciones tal cual; por ejemplo, los espacios adicionales al final de una línea todavía se muestran como errores (resaltados en rojo) en la diferencia.

(Otras respuestas han aludido a esto, pero lo anterior es exactamente cómo establecer la configuración. Para establecer la configuración de un solo proyecto, omita el --global.)

EDITAR :

Después de muchas dificultades en el final de línea, he tenido la mejor suerte, cuando trabajo en un equipo .NET, con esta configuración:

  • NO configuración core.eol
  • NO configuración core.whitespace
  • NO configuración core.autocrlf
  • Al ejecutar el instalador de Git para Windows, obtendrá estas tres opciones:
    • Verifique el estilo de Windows, confirme los finales de línea de estilo Unix <- elija este
    • Pague como está, confirme los finales de línea de estilo Unix
    • Realizar el pago tal cual, confirmar tal cual

Si necesita usar la configuración de espacios en blanco, probablemente debería habilitarla solo por proyecto si necesita interactuar con TFS. Solo omita el --global:

git config core.whitespace cr-at-eol

Si necesita eliminar algunas configuraciones del núcleo. *, La forma más fácil es ejecutar este comando:

git config --global -e

Esto abre su archivo global .gitconfig en un editor de texto, y puede eliminar fácilmente las líneas que desea eliminar. (O puede poner '#' delante de ellos para comentarlos).


30
Para aquellos que encuentran esto ahora, vale la pena señalar que el Pedido de estilo de Windows, cometen estilo Unix finales de línea de auto-sets core.autocrlfatrue
K. carpintero

14
Tenga en cuenta que la línea git config --global core.whitespace cr-at-eoldesactivaría otras configuraciones predeterminadas. Hay tres valores predeterminados: blank-at-eol, blank-at-eof y space-before-tab. Entonces, para habilitar cr-at-eol mientras se mantienen los otros que necesitaría usar git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax

2
Para mi proyecto (estaba finalizando la compra en Windows y lo estoy viendo en Linux), cr-at-eolme deshice ^Mal final de las líneas git diff, pero GIT todavía mostró esas líneas como diferentes, aunque el final de la línea fue la única diferencia.
Jānis Elmeris

SourceInsight sigue presionando el carácter ^ M, y git todavía muestra la diferencia en los finales de línea. El comando de @ Zitrax es la respuesta correcta a mi caso, git diff muestra una salida agradable y limpia.
Lê Quang Duy

3
Creo que git necesita un poco más de complejidad, algunas configuraciones más conflictivas para el final de línea. Creo que git debería estar más preocupado por mis espacios en blanco. Por ejemplo, arroje un error fatal no relacionado y deje el repositorio en un estado corrupto cuando encuentre terminaciones de línea Mac en una máquina Windows (pero no Linux). Quiero decir, ¿por qué usaría un VCS que me importaría su negocio y me permitiría usar las terminaciones de línea que desee? Veo que lo están intentando, pero deberían incluir media docena más de comportamientos de final de línea para resolver un problema que no existe. ¡Ya casi están allí! Seguid así.
Rolf

125

Intenta git diff --ignore-space-at-eol, o git diff --ignore-space-change, o git diff --ignore-all-space.


22
Nada de eso afecta realmente al personaje que identifica la nueva línea.
nes1983

44
También probé con "-w" pero no tuve suerte, todavía lo trata como una sola línea. El próximo proyecto que debo recordar es que nunca debe introducir ningún CR en el código fuente.
neoneye

3
Sólo recuerde git config --global core.autocrlf verdadera, o error a la gente git hasta que lo convierten en defecto :)
nes1983

10
Esto resolvió mi problema sin tener que cambiar mi autocrlfconfiguración. ¡Gracias!
nneonneo

11
estas banderas no tienen ningún efecto para mí ... todavía muestra ^ M como diferencias
Magnus

103

Ver también:

core.whitespace = cr-at-eol

o equivalente,

[core]
    whitespace = cr-at-eol

donde whitespaceestá precedido por un carácter de tabulación .


44
Sí, ¡esto hizo que la herramienta git diff (también usada en git show) dejara de molestarme sobre los ^Ms en las líneas cambiadas! :)
Rijk

2
por alguna razón esto no funcionó para mí. Intenté ambos con = y no = signo. git difftodavía muestra ^ M caracteres.
Dennis

66
Dos maneras de hacer esto: una, agregue la línea de arriba literalmente a su .gitconfig en .git / config, o en ~ / .gitconfig; dos, git config --global core.whitespace cr-at-eol(donde --global es opcional si solo lo quieres en el repositorio en el que estás)
K. Carpenter

Esto funcionó para mí en Windows 7, aunque solo lo puse debajo [core]para poder reemplazar el core.prefijo con un carácter TAB.
Rufflewind

Esta pregunta estaba por encima de la forma de ocultar ^Men git diff, no se trata de cómo no poner en ^ M en el primer lugar. Eso significa que la respuesta aceptada de cambio core.autocrlfno es la mejor porque altera silenciosamente los archivos sin la confirmación del usuario.
deddebme

45

¿Por qué tienes estos ^Men tu git diff?

En mi caso, estaba trabajando en un proyecto que se desarrolló en Windows y usé OS X. Cuando cambié algún código, vi ^Mal final de las líneas que agregué git diff. Creo que ^Mestaban apareciendo porque eran terminaciones de línea diferentes que el resto del archivo. Debido a que el resto del archivo se desarrolló en Windows, usó CRterminaciones de línea, y en OS X usa LFterminaciones de línea.

Aparentemente, el desarrollador de Windows no usó la opción " Checkout estilo Windows, confirmar terminaciones de línea estilo Unix " durante la instalación de Git.

Entonces, ¿qué debemos hacer al respecto?

Puede hacer que los usuarios de Windows reinstalen git y usen la opción " Finalizar línea al estilo de Windows, confirmar estilo Unix ". Esto es lo que preferiría, porque veo a Windows como una excepción en sus caracteres de final de línea y Windows soluciona su propio problema de esta manera.

Sin embargo, si opta por esta opción, debe corregir los archivos actuales (porque todavía usan los CRfinales de línea). Hice esto siguiendo estos pasos:

  1. Elimine todos los archivos del repositorio, pero no de su sistema de archivos.

    git rm --cached -r .
    
  2. Agregue un .gitattributesarchivo que haga cumplir ciertos archivos para usar LFcomo terminaciones de línea. Pon esto en el archivo:

    *.ext text eol=crlf
    

    Reemplace .extcon las extensiones de archivo que desea hacer coincidir.

  3. Agregue todos los archivos nuevamente.

    git add .
    

    Esto mostrará mensajes como este:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Puede eliminar el .gitattributesarchivo a menos que tenga usuarios obstinados de Windows que no quieran usar la opción " Finalizar línea estilo Confirmar Windows, confirmar estilo Unix ".

  5. Comprometerse y empujarlo todo.

  6. Elimine y revise los archivos aplicables en todos los sistemas donde se usan. En los sistemas Windows, asegúrese de que ahora usen la opción " Finalizar línea al estilo de Windows, confirmar estilo Unix ". También debe hacer esto en el sistema donde ejecutó estas tareas porque cuando agregó los archivos, git dijo:

    The file will have its original line endings in your working directory.
    

    Puede hacer algo como esto para eliminar los archivos:

    git ls | grep ".ext$" | xargs rm -f
    

    Y luego esto para recuperarlos con las terminaciones de línea correctas:

    git ls | grep ".ext$" | xargs git checkout
    

    Por supuesto, reemplazando .extcon la extensión que desee.

Ahora su proyecto solo usa LFcaracteres para los finales de línea, y los CRcaracteres desagradables nunca volverán :).

La otra opción es hacer cumplir las terminaciones de línea de estilo de Windows. También puede usar el .gitattributesarchivo para esto.

Más información: https://help.github.com/articles/dealing-with-line-endings/#platform-all


44
Para arreglar todas las terminaciones de línea en un archivo específico, si usa Sublime Text, puede ir a View-> Line Endingsy hacer clic en Unix.
Topher Hunt

¿Qué significa esto exactamente ^M? ¿Es una nueva línea de Windows o Linux? ¿O es simplemente una nueva línea "diferente" en comparación con las otras nuevas líneas en el archivo?
buhtz

Buena, creo que es solo una nueva línea "diferente" (diferente a la mayoría de los demás)
gitaarik

-1 ya que reinstalar git para lograrlo git config --global core.autocrlf truees excesivo, y la anti-Windows / anti- CRcampaña parece tangencial a la pregunta.
RJFalconer

41

¿Hay una opción como "tratar ^ M como nueva línea al diferenciar"?

Habrá uno con Git 2.16 (Q1 2018), ya que la " diff" familia de comandos aprendió a ignorar las diferencias en el retorno de carro al final de la línea.

Ver commit e9282f0 (26 de octubre de 2017) por Junio ​​C Hamano ( gitster) .
Ayudado por: Johannes Schindelin ( dscho) .
(Fusionada por Junio ​​C Hamano - gitster- en commit 10f65c2 , 27 nov 2017)

diff: --ignore-cr-at-eol

Una nueva opción --ignore-cr-at-eolle dice a la maquinaria diff que trate un retorno de carro al final de una línea (completa) como si no existiera.

Al igual que otras " --ignore-*" opciones para ignorar varios tipos de diferencias de espacios en blanco, esto ayudará a revisar los cambios reales que realizó sin distraerse con la CRLF<->LFconversión espuria realizada por su programa de edición.


@kaartic ¡Gracias por editar la respuesta y hacer referencia a la confirmación correcta!
VonC

3
Si bien en general es una buena práctica establecer git config --global core.autocrlf truecomo en la respuesta aceptada, esto responde a la pregunta del OP más directamente: '¿Hay una opción como "tratar ^ M como nueva línea cuando difiere"?
drkvogel

1
A partir de Git 2.20 esto no oculta ^ M's
user1944491

@ user1944491 No noté ninguna regresión, lo que significa que todavía ignora eol al diferir con esta opción en Git 2.26.
VonC

@VonC El uso de este argumento en el comando git diff no funcionó. Tampoco configuró mi valor core.whitespace git version 2.20.1 (Apple Git-117)pero al agregar la respuesta core.pager de Jason Pyeron lo solucionó. YMMV obviamente.
user1944491

26

TL; DR

Cambie el código fuente core.pagera "tr -d '\r' | less -REX", no

Esta es la razón por

Los molestos ^ M que se muestran son un artefacto de la coloración y el localizador. ingrese la descripción de la imagen aquí Es causado por less -Runa opción predeterminada de buscapersonas git. (el localizador predeterminado de git es less -REX)

Lo primero a tener en cuenta es que git diff -bno mostrará cambios en el espacio en blanco (por ejemplo, \ r \ n vs \ n)

preparar:

git clone https://github.com/CipherShed/CipherShed
cd CipherShed

Una prueba rápida para crear un archivo Unix y cambiar las terminaciones de línea no mostrará cambios con git diff -b:

echo -e 'The quick brown fox\njumped over the lazy\ndogs.' > test.txt
git add test.txt
unix2dos.exe test.txt
git diff -b test.txt

Notamos que forzar una tubería a menos no muestra el ^ M, pero habilita el color y less -Rsí:

git diff origin/v0.7.4.0 origin/v0.7.4.1 | less
git -c color.ui=always diff origin/v0.7.4.0 origin/v0.7.4.1 | less -R

La solución se muestra usando una tubería para quitar el \ r (^ M) de la salida:

git diff origin/v0.7.4.0 origin/v0.7.4.1
git -c core.pager="tr -d '\r' | less -REX"  diff origin/v0.7.4.0 origin/v0.7.4.1

Es una alternativa imprudente usar less -r, porque pasará por todos los códigos de control, no solo los códigos de color.

Si solo desea editar su archivo de configuración git directamente, esta es la entrada para actualizar / agregar:

[core]
        pager = tr -d '\\r' | less -REX

Tuve este problema en un repositorio donde algunos de los archivos tenían \r\nterminaciones de línea y algunos tenían \nterminaciones de línea (no sé si eso es relevante); Las diferencias entre las primeras mostraban las ^Mlíneas modificadas (es decir, las +líneas). core.autocrlfse estableció en true. Correr git config core.pager "tr -d '\r' | less -REX"se libró de los molestos ^Ms. ¡Gracias!
labreuer 01 de

55
Gracias por esto. Esta es la única respuesta si debe trabajar con diferentes finales de línea en sus repositorios, por ejemplo, utiliza el proceso de pago tal cual, se compromete tal cual, a propósito.
Mike

git diff -bes lo que estaba buscando, pero aprecio la explicación detallada.
Martin Burch

¡Esta es la respuesta! Gracias. la bandera -b no me funcionó.
Chris

¡Si! De todas las respuestas a esta pregunta, la modificación de la [core]sección del archivo git "config" agregando pager = tr -d '\\r' | less -REXfue la única respuesta que funcionó para mí. ¡Gracias!
Rashiki

13

Luché con este problema durante mucho tiempo. Con mucho, la solución más fácil es no preocuparse por los caracteres ^ M y simplemente usar una herramienta de diferencia visual que pueda manejarlos.

En lugar de escribir:

git diff <commitHash> <filename>

tratar:

git difftool <commitHash> <filename>

1
¡Gracias! También ejecuté "git difftool" y básicamente comparó todos los archivos modificados en un bucle
Bhanuprakash D


2

Como señaló VonC, esto ya se ha incluido en git 2.16+. Desafortunadamente, el nombre de la opción ( --ignore-cr-at-eol) difiere del utilizado por GNU diff al que estoy acostumbrado ( --strip-trailing-cr).

Cuando me enfrenté a este problema, mi solución fue invocar la diferencia de GNU en lugar de la diferencia incorporada de git, porque mi git es anterior a 2.16. Lo hice usando esta línea de comando:

GIT_EXTERNAL_DIFF='diff -u --strip-trailing-cr "$2" "$5";true;#' git diff --ext-diff

Eso permite usar --strip-trailing-cry cualquier otra opción de GNU diff.

También hay esta otra manera:

git difftool -y -x 'diff -u --strip-trailing-cr'

pero no usa la configuración de buscapersonas configurada, por eso prefiero la primera.


Alternativa interesante a mi respuesta. Votado
VonC
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.