Cómo funcionan las conversiones de final de línea con git core.autocrlf entre diferentes sistemas operativos


220

He leído muchas preguntas y respuestas diferentes sobre Stack Overflow, así como documentación de git sobre cómo funciona la configuración core.autocrlf .

Este es mi entendimiento de lo que he leído:

Los clientes Unix y Mac OSX (pre-OSX usan CR) usan terminaciones de línea LF.
Los clientes de Windows usan finales de línea CRLF.

Cuando core.autocrlf se establece en verdadero en el cliente, el repositorio de git siempre almacena archivos en formato de terminación de línea LF y las terminaciones de línea en archivos en el cliente se convierten de un lado a otro al finalizar / confirmar para clientes (es decir, Windows) que usan -LF terminaciones de línea, sin importar el formato que tengan los archivos de terminación de línea en el cliente (esto no está de acuerdo con la definición de Tim Clem; consulte la actualización a continuación).

Aquí hay una matriz que intenta documentar lo mismo para la configuración de 'entrada' y 'falsa' de core.autocrlf con signos de interrogación donde no estoy seguro del comportamiento de conversión de final de línea.

Mis preguntas son:

  1. ¿Cuáles deberían ser los signos de interrogación?
  2. ¿Es esta matriz correcta para los "signos que no son de interrogación"?

Actualizaré los signos de interrogación de las respuestas a medida que se forme un consenso.

                       valor core.autocrlf
            entrada verdadera falsa
-------------------------------------------------- --------
cometer | convertir? ?
nuevo | a LF (¿convertir a LF?) (¿sin conversión?)

cometer | convertir a ? No
existente | Conversión de LF (¿convertir a LF?)

pago | convertir a ? No
existente | Conversión CRLF (¿sin conversión?)

Realmente no estoy buscando opiniones sobre los pros y los contras de los diversos entornos. Solo estoy buscando datos que aclaren cómo esperar que git funcione con cada una de las tres configuraciones.

-

Actualización 17/04/2012 : Después de leer el artículo de Tim Clem vinculado por JJD en los comentarios, modifiqué algunos de los valores en los valores "desconocidos" en la tabla anterior, así como también cambié "pago existente | verdadero para convertir a CRLF en lugar de convertir a cliente ". Aquí están las definiciones que da, que son más claras que cualquier cosa que haya visto en otros lugares:

core.autocrlf = false

Este es el valor predeterminado, pero se alienta a la mayoría de las personas a cambiar esto inmediatamente. El resultado del uso de false es que Git nunca se mete con las terminaciones de línea en su archivo. Puede registrar archivos con LF o CRLF o CR o alguna combinación aleatoria de esos tres y a Git no le importa. Esto puede hacer que las diferencias sean más difíciles de leer y las fusiones sean más difíciles. La mayoría de las personas que trabajan en un mundo Unix / Linux usan este valor porque no tienen problemas de CRLF y no necesitan que Git haga un trabajo adicional cada vez que los archivos se escriben en la base de datos de objetos o se escriben en el directorio de trabajo.

core.autocrlf = true

Esto significa que Git procesará todos los archivos de texto y se asegurará de que CRLF se reemplace con LF al escribir ese archivo en la base de datos de objetos y volverá a convertir todos los LF en CRLF al escribir en el directorio de trabajo. Esta es la configuración recomendada en Windows porque garantiza que su repositorio se pueda usar en otras plataformas mientras conserva CRLF en su directorio de trabajo.

core.autocrlf = input

Esto significa que Git procesará todos los archivos de texto y se asegurará de que CRLF se reemplace con LF al escribir ese archivo en la base de datos de objetos. Sin embargo, no hará lo contrario. Cuando vuelva a leer los archivos de la base de datos de objetos y los escriba en el directorio de trabajo, seguirán teniendo LF para indicar el final de la línea. Esta configuración se usa generalmente en Unix / Linux / OS X para evitar que los CRLF se escriban en el repositorio. La idea es que si pega el código de un navegador web y accidentalmente obtiene CRLF en uno de sus archivos, Git se aseguraría de que fueran reemplazados por LF cuando escribiera en la base de datos de objetos.

El artículo de Tim es excelente, lo único que se me ocurre es que él asume que el repositorio está en formato LF, lo cual no es necesariamente cierto, especialmente para proyectos de Windows.

La comparación del artículo de Tim con la respuesta más votada hasta la fecha por jmlane muestra un acuerdo perfecto sobre la configuración verdadera y de entrada y el desacuerdo sobre la configuración falsa.


77
Mantenerse autocrlfen falso parece mucho más fácil;) stackoverflow.com/questions/2333424/…
VonC

@VonC: He leído eso y creo que lo entiendo, pero no necesariamente puedo tomar la decisión. Trabajo con repositorios git que no controlo y que requieren que establezca el valor de cierta manera.
Michael Maddox

55
¿No sería bueno si Windows también se normalizara a LF? Mac solía ser CR (v10 anterior) pero ahora está normalizado a LF.
Brett Ryan

3
Necesito agregar un enlace al gran artículo de Timothy Clem . Por favor, lea todo sobre Mind the End of Your Line .
JJD

1
Escenario: soy un desarrollador de Linux / Windows dividido. Solo uso editores de texto que pueden reconocer ambos tipos de terminaciones de línea (IE. Vim, eclipse). Solo necesito (quiero) trabajar con archivos que terminan en LF. Actualmente tengo core.autocrlf = input establecido en mi configuración global de git. ¿Estoy bien para ir? ¿Alguna vez tendré un conflicto?
Chris

Respuestas:


128

La mejor explicación de cómo core.autocrlffunciona se encuentra en la página de manual de gitattributes , en la textsección de atributos.

Así es como core.autocrlfparece funcionar actualmente (o al menos desde v1.7.2 por lo que sé):

  • core.autocrlf = true
    1. Los archivos de texto extraídos del repositorio que solo tienen LFcaracteres están normalizados CRLFen su árbol de trabajo; los archivos que contienen CRLFen el repositorio no serán tocados
    2. Los archivos de texto que sólo tienen LFcaracteres en el repositorio, se normalizaron a partir CRLFde LFcuando vuelva a estar comprometido con el repositorio. Los archivos que contienen CRLFen el repositorio se confirmarán intactos.
  • core.autocrlf = input
    1. Los archivos de texto extraídos del repositorio mantendrán los caracteres EOL originales en su árbol de trabajo.
    2. Los archivos de texto en su árbol de trabajo con CRLFcaracteres se normalizan LFcuando se devuelven al repositorio.
  • core.autocrlf = false
    1. core.eol dicta caracteres EOL en los archivos de texto de su árbol de trabajo.
    2. core.eol = nativede forma predeterminada, lo que significa que las EOL de Windows están CRLFy * nix EOL están LFen árboles de trabajo.
    3. La gitattributesconfiguración del repositorio determina la normalización de caracteres EOL para las confirmaciones en el repositorio (el valor predeterminado es la normalización de los LFcaracteres).

Acabo de investigar este problema recientemente y también encuentro que la situación es muy complicada. La core.eolconfiguración definitivamente ayudó a aclarar cómo git maneja los caracteres EOL.


3
for autocrlf = true no debería ser lo siguiente? Los archivos de texto que solo tienen caracteres CRLF EOL en el repositorio se normalizan de CRLF a LF cuando se vuelven a confirmar en el repositorio. Los archivos que contienen LF en el repositorio se confirmarán intactos.
Piotr Lewandowski

2
Para mí, incluso si autocrlf = false git estaba convirtiendo la EOL a CRLF. Después de leer esta respuesta, me di cuenta de que mi archivo .gitattribute tenía text = auto set que estaba causando el problema.
irsis

1
Porque core.autocrlf = false, si no tengo un gitattributesarchivo, ¿significa que no habrá normalización? ¿O significa que usará la normalización predeterminada?
Chin

¿No debería el .gitattributesarchivo tener prioridad sobre la core.autocrlfconfiguración?
Qwerty

63

El tema de las EOL en proyectos de plataforma mixta ha hecho que mi vida sea miserable durante mucho tiempo. Los problemas suelen surgir cuando ya hay archivos con diferentes y mixtos EOLs ya en el repositorio. Esto significa que:

  1. El repositorio puede tener diferentes archivos con diferentes EOL
  2. Algunos archivos en el repositorio pueden tener EOL mixtos, por ejemplo, una combinación de CRLFy LFen el mismo archivo.

Cómo sucede esto no es el problema aquí, pero sucede.

Ejecuté algunas pruebas de conversión en Windows para los diversos modos y sus combinaciones.
Esto es lo que obtuve, en una tabla ligeramente modificada:

                 El | Conversión resultante cuando | Conversión resultante cuando
                 El | comprometer archivos con varios | echando un vistazo desde el repositorio -
                 El | EOLs EN repo y | con archivos mixtos y
                 El | valor core.autocrlf: | valor core.autocrlf:           
-------------------------------------------------- ------------------------------
Archivo | cierto | entrada | falso | cierto | entrada | falso
-------------------------------------------------- ------------------------------
Windows-CRLF | CRLF -> LF | CRLF -> LF | tal cual | tal cual | tal cual | como es
Unix -LF | tal cual | tal cual | tal cual | LF -> CRLF | tal cual | como es
Mac -CR | tal cual | tal cual | tal cual | tal cual | tal cual | como es
Mixto-CRLF + LF | tal cual | tal cual | tal cual | tal cual | tal cual | como es
Mixto-CRLF + LF + CR | tal cual | tal cual | tal cual | tal cual | tal cual | como es

Como puede ver, hay 2 casos en los que la conversión ocurre en commit (3 columnas a la izquierda). En el resto de los casos, los archivos se confirman tal cual.

Al finalizar la compra (3 columnas a la derecha), solo hay 1 caso donde la conversión ocurre cuando:

  1. core.autocrlfes true y
  2. el archivo en el repositorio tiene la LFEOL.

Lo más sorprendente para mí, y sospecho, la causa de muchos problemas de EOL es que no hay una configuración en la que se normalicen EOL mixtos como CRLF+ LF.

Tenga en cuenta también que las EOL de Mac "antiguas" de CRsolo nunca se convierten.
Esto significa que si una secuencia de comandos de conversión EOL mal escrita intenta convertir un archivo final mixto con CRLFs + LFs, simplemente convirtiendo LFs a CRLFs, entonces dejará el archivo en modo mixto con "solitario" CRdonde sea que CRLFse haya convertido CRCRLF.
Git no convertirá nada, ni siquiera en el truemodo, y continúa el caos EOL. Esto realmente me sucedió y desordenó mis archivos realmente mal, ya que a algunos editores y compiladores (por ejemplo, VS2010) no les gustan las EOL de Mac.

Supongo que la única forma de manejar realmente estos problemas es normalizar ocasionalmente todo el repositorio revisando todos los archivos en modo inputo false, ejecutando una normalización adecuada y volviendo a confirmar los archivos modificados (si los hay). En Windows, presumiblemente reanude el trabajo con core.autocrlf true.


44
Excelente respuesta, pero una frase con la que no puedo estar de acuerdo es En Windows, presumiblemente reanude el trabajocore.autocrlf true . Personalmente, creo que inputdebe usarse siempre.
G. Demecki

39

Las cosas están a punto de cambiar en el frente de "conversión eol", con el próximo Git 1.7.2 :

Se core.eolestá agregando / evolucionando una nueva configuración :

Este es un reemplazo para el core.eolcommit 'Agregar " " variable de configuración' que se encuentra actualmente pu(el último en mi serie).
En lugar de implicar que " core.autocrlf=true" es un reemplazo para " * text=auto", se hace explícito el hecho de que autocrlfes solo para usuarios que desean trabajar con CRLF en su directorio de trabajo en un repositorio que no tiene normalización de archivos de texto .
Cuando está habilitado, se ignora "core.eol".

Introduzca una nueva variable de configuración, " core.eol", que permita al usuario establecer qué terminaciones de línea usar para los archivos normalizados de fin de línea en el directorio de trabajo.
El valor predeterminado es " native", lo que significa CRLF en Windows y LF en cualquier otro lugar. Tenga en cuenta que " core.autocrlf" anula core.eol.
Esto significa que:

[core]
  autocrlf = true

coloca los CRLF en el directorio de trabajo incluso si core.eolestá configurado en " lf".

core.eol:

Establece el tipo de final de línea para usar en el directorio de trabajo para los archivos que tienen textestablecida la propiedad.
Las alternativas son 'lf', 'crlf' y 'native', que utiliza el final de línea nativo de la plataforma.
El valor por defecto es native.


Se están considerando otras evoluciones :

Para 1.8, consideraría hacer core.autocrlfsimplemente encienda la normalización y salir de la línea de directorio de trabajo que termina decisión de core.eol, pero que voy a romper las configuraciones de las personas.


git 2.8 (marzo de 2016) mejora la forma en que core.autocrlfinfluye en la eol:

Consulte commit 817a0c7 (23 de febrero de 2016), commit 6e336a5 , commit df747b8 , commit df747b8 (10 de febrero de 2016), commit df747b8 , commit df747b8 (10 de febrero de 2016) y commit 4b4024f , commit bb211b4 , commit 92cce13 , commit 320d39c , commit 4b4024f , commit 4b4024f commit bb211b4 , commit 92cce13 , commit 320d39c (05 de febrero de 2016) por Torsten Bögershausen ( tboegi) .
(Fusionada por Junio ​​C Hamano - gitster- en commit c6b94eb26 de febrero de 2016)

convert.c: refactor crlf_action

Refactorizar la determinación y el uso de crlf_action.
Hoy, cuando no crlfse establece ningún atributo " " en un archivo, crlf_actionse establece en CRLF_GUESS. Use en su CRLF_UNDEFINEDlugar y busque " text" o " eol" como antes.

Reemplace el CRLF_GUESSuso anterior:

CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT

Deje más claro, qué es qué, definiendo:

- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
                   and core.eol is evaluated and one of CRLF_BINARY,
                   CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY    : No processing of line endings.
- CRLF_TEXT      : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO      : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true  (no attributes)

Como torek agrega en los comentarios :

todas estas traducciones (cualquier conversión de EOL eol=o autocrlfconfiguración, y " clean" filtros) se ejecutan cuando los archivos se mueven del árbol de trabajo al índice , es decir, durante git addy no en el git commitmomento.
(Tenga en cuenta que git commit -ao --onlyo --includehacer archivos de complemento al índice en ese momento, sin embargo.)

Para obtener más información al respecto, consulte " Cuál es la diferencia entre autocrlf y eol ".


18
Esto, desafortunadamente, no agrega claridad para mí. Parece que están diciendo que hay problemas con la implementación actual (no está claro cuáles son esos problemas) y están aumentando la complejidad en un esfuerzo por resolver esos problemas no especificados. En mi opinión, la configuración core.autocrlf ya es demasiado compleja y está poco documentada, y esa situación parece empeorar. Gracias de nuevo por el aviso.
Michael Maddox

1
Esto no parece ser una solución satisfactoria y parece tener los mismos problemas que core.autocrlf. Mi preferencia sería si git nunca modificara algo automáticamente, pero advertiría al usuario que desea agregar o confirmar las terminaciones de línea incorrectas. Por lo tanto, necesitaría una opción de línea de comandos para permitir que "git add" agregue las terminaciones de línea "incorrectas". (probablemente git add es el mejor lugar para verificar esto que git commit)
donquixote

Esto obligaría al usuario respectivo a cambiar la configuración de su editor y realmente resolver el problema. Si bien permitiría dejar las terminaciones de línea "incorrectas" para archivos de terceros, o que ya se hayan registrado en el repositorio.
donquixote

@donquixote nuevamente, estoy de acuerdo. Pero core.eolse trata de "modificar automáticamente" solo lo que declaras explícitamente en un .gitattributesarchivo. Esto es diferente de lo core.autocrlfque se aplica a cualquier archivo en el repositorio. Es un proceso declarativo.
VonC

1
@donquixote: Me doy cuenta de que esto es bastante antiguo, pero solo leo tu comentario ahora. De hecho, todas estas traducciones (cualquier conversión EOL de la configuración eol = o autocrlf, y los filtros "limpios") se ejecutan cuando los archivos se mueven del árbol de trabajo al índice, es decir, durante el tiempo git addy no en el git commitmomento. (Tenga en cuenta que git commit -ao --onlyo --includehacer archivos de complemento al índice en ese momento, sin embargo.) Por lo que vale, tú, yo y Linus Torvalds todos odian la idea de un VCS vez modificando lo que se ha comprometido. Pero hay todos esos usuarios de Windows ... :-)
torek

34

core.autocrlfel valor no depende del tipo de sistema operativo, pero el valor predeterminado de Windows es truey para Linux - input. Exploré 3 valores posibles para los casos de confirmación y pago y esta es la tabla resultante:

╔═══════════════╦══════════════╦══════════════╦══════════════╗
║ core.autocrlf ║     false    ║     input    ║     true     ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => LF   ║
║ git commit    ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => LF   ║ CRLF => LF   ║
╠═══════════════╬══════════════╬══════════════╬══════════════╣
║               ║ LF   => LF   ║ LF   => LF   ║ LF   => CRLF ║
║ git checkout  ║ CR   => CR   ║ CR   => CR   ║ CR   => CR   ║
║               ║ CRLF => CRLF ║ CRLF => CRLF ║ CRLF => CRLF ║
╚═══════════════╩══════════════╩══════════════╩══════════════╝

55
Breve resumen en palabras: los archivos con CRsolo nunca se tocan. falsenunca toca las terminaciones de línea. truesiempre se compromete como LFy se retira como CRLF. Y inputsiempre se compromete LFy se retira tal como está.
Furkan Kambay

7

Aquí está mi comprensión hasta ahora, en caso de que ayude a alguien.

core.autocrlf=true y core.safecrlf = true

Tiene un repositorio donde todas las terminaciones de línea son iguales , pero trabaja en diferentes plataformas. Git se asegurará de que las terminaciones de sus líneas se conviertan en las predeterminadas para su plataforma. ¿Por qué importa esto? Digamos que crea un nuevo archivo. El editor de texto en su plataforma utilizará sus finales de línea predeterminados. Cuando lo registra, si no tiene core.autocrlf establecido en verdadero, ha introducido una inconsistencia de final de línea para alguien en una plataforma que por defecto es un final de línea diferente. Siempre configuro safecrlf también porque me gustaría saber que la operación crlf es reversible. Con estas dos configuraciones, git está modificando sus archivos, pero verifica que las modificaciones sean reversibles .

core.autocrlf=false

Tiene un repositorio que ya tiene terminaciones de línea mixtas registradas y corregir las terminaciones de línea incorrectas podría romper otras cosas. Es mejor no decirle a Git que convierta las terminaciones de línea en este caso, porque entonces exacerbará el problema que fue diseñado para resolver, haciendo que las diferencias sean más fáciles de leer y las fusiones sean menos dolorosas. Con esta configuración, git no modifica sus archivos .

core.autocrlf=input

No uso esto porque la razón de esto es para cubrir un caso de uso en el que creó un archivo que tiene terminaciones de línea CRLF en una plataforma que por defecto tiene terminaciones de línea LF. En cambio, prefiero que mi editor de texto siempre guarde nuevos archivos con los valores predeterminados de final de línea de la plataforma.


3

No, la respuesta de @jmlane es incorrecta.

Para Checkin (git add, git commit):

  1. si la textpropiedad es Set, Set value to 'auto', la conversión se produce en el archivo se ha confirmado con 'CRLF'
  2. si la textpropiedad es Unset: no pasa nada, enen paraCheckout
  3. si la textpropiedad es Unspecified, la conversión depende decore.autocrlf
    1. si autocrlf = input or autocrlf = true, la conversión solo ocurre cuando el archivo en el repositorio es 'LF', si ha sido 'CRLF', no pasará nada.
    2. si autocrlf = false, no pasa nada

Para Checkout:

  1. si la textpropiedad es Unset: no pasa nada.
  2. Si textla propiedad es Set, Set value to 'auto: depende core.autocrlf, core.eol.
    1. core.autocrlf = input: no pasa nada
    2. core.autocrlf = true: la conversión solo ocurre cuando el archivo en el repositorio es 'LF', 'LF' -> 'CRLF'
    3. core.autocrlf = false: la conversión solo ocurre cuando el archivo en el repositorio es 'LF', 'LF' -> core.eol
  3. si la textpropiedad es Unspecified, depende de core.autocrlf.
    1. lo mismo que 2.1
    2. lo mismo que 2.2
    3. Ninguno, no pasa nada, core.eol no es efectivo cuando la textpropiedad esUnspecified

Comportamiento por defecto

Entonces, el comportamiento predeterminado es textpropiedad es Unspecifiedy core.autocrlf = false:

  1. para registrarse, no pasa nada
  2. para el pago, no pasa nada

Conclusiones

  1. si textse establece la propiedad, el comportamiento de registro depende de sí mismo, no de autocrlf
  2. autocrlf o core.eol es para comportamiento de pago, y autocrlf> core.eol

2

Hice algunas pruebas tanto en Linux como en Windows. Utilizo un archivo de prueba que contiene líneas que terminan en LF y también líneas que terminan en CRLF.
El archivo se confirma, se elimina y luego se retira. El valor de core.autocrlf se establece antes de la confirmación y también antes del pago. El resultado está abajo.

commit core.autocrlf false, remove, checkout core.autocrlf false: LF=>LF   CRLF=>CRLF  
commit core.autocrlf false, remove, checkout core.autocrlf input: LF=>LF   CRLF=>CRLF  
commit core.autocrlf false, remove, checkout core.autocrlf true : LF=>LF   CRLF=>CRLF  
commit core.autocrlf input, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF  
commit core.autocrlf input, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF  
commit core.autocrlf input, remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF  
commit core.autocrlf true, remove, checkout core.autocrlf false: LF=>LF   CRLF=>LF  
commit core.autocrlf true, remove, checkout core.autocrlf input: LF=>LF   CRLF=>LF  
commit core.autocrlf true,  remove, checkout core.autocrlf true : LF=>CRLF CRLF=>CRLF  
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.