Como as conversões de término de linha funcionam com o git core.autocrlf entre diferentes sistemas operacionais

Eu li um monte de perguntas e respostas diferentes sobre o Stack Overflow, bem como a documentação do git sobre como funciona a configuração core.autocrlf .

Este é o meu entendimento pelo que li:

Os clientes Unix e Mac OSX (pré-OSX usa CR) usam finais de linha LF.
Clientes Windows usam finais de linha CRLF.

Quando o core.autocrlf é configurado como true no cliente, o repository git sempre armazena arquivos no formato final da linha LF e os finais de linha nos arquivos no cliente são convertidos para frente e para trás no check out / commit para clientes (isto é, Windows) que usam -LF terminações de linha, não importa o formato dos arquivos de término de linha no cliente (isso não está de acordo com a definição de Tim Clem – veja a atualização abaixo).

Aqui está uma matriz que tenta documentar o mesmo para as configurações ‘input’ e ‘false’ do core.autocrlf com pontos de interrogação em que não tenho certeza do comportamento de conversão de fim de linha.

Minhas perguntas são:

  1. Quais devem ser os pontos de interrogação?
  2. Esta matriz é correta para os “não-pontos de interrogação”?

Vou atualizar os pontos de interrogação das respostas, já que o consenso parece estar formado.

                        valor core.autocrlf
             input verdadeira falsa
 -------------------------------------------------- --------
 commit |  converter?  ?
 novo |  para LF (converter para LF?) (sem conversão?)

 commit |  converter para ?  não 
 existente |  Conversão LF (convert para LF?)

 checkout |  converter para ?  não
 existente |  Conversão CRLF (sem conversão?)

Eu não estou realmente procurando opiniões sobre os prós e contras das várias configurações. Estou apenas procurando dados que deixem claro como esperar que o git opere com cada uma das três configurações.

Atualização 17/04/2012 : Depois de ler o artigo de Tim Clem linkado por JJD nos comentários, modifiquei alguns dos valores nos valores “desconhecidos” na tabela acima, além de alterar “checkout existing | true para converter para CRLF em vez de converter para cliente “. Aqui estão as definições que ele dá, que são mais claras do que qualquer coisa que vi em outro lugar:

core.autocrlf = false

Este é o padrão, mas a maioria das pessoas é incentivada a mudar isso imediatamente. O resultado de usar false é que o Git nunca mexeu com os finais de linha no seu arquivo. Você pode verificar arquivos com LF ou CRLF ou CR ou alguma mistura aleatória desses três e o Git não se importa. Isso pode tornar os diffs mais difíceis de ler e mesclar mais difíceis. A maioria das pessoas que trabalham em um mundo Unix / Linux usam esse valor porque não têm problemas de CRLF e não precisam que o Git esteja fazendo um trabalho extra sempre que os arquivos forem gravados no database de objects ou gravados no diretório de trabalho.

core.autocrlf = true

Isso significa que o Git processará todos os arquivos de texto e garantirá que o CRLF seja substituído por LF ao gravar esse arquivo no database de objects e transformar todo o LF de volta no CRLF ao escrever no diretório de trabalho. Essa é a configuração recomendada no Windows porque garante que seu repository possa ser usado em outras plataformas enquanto mantém o CRLF em seu diretório de trabalho.

core.autocrlf = input

Isso significa que o Git processará todos os arquivos de texto e garantirá que o CRLF seja substituído por LF ao gravar esse arquivo no database de objects. Não fará, no entanto, o contrário. Quando você lê os arquivos do database de objects e os grava no diretório de trabalho, eles ainda terão LFs para indicar o fim da linha. Essa configuração é geralmente usada no Unix / Linux / OS X para impedir que os CRLFs sejam gravados no repository. A idéia é que, se você colasse código de um navegador da Web e acidentalmente colocasse os CRLFs em um de seus arquivos, o Git se certificaria de que eles foram substituídos por LFs quando você escreveu no database de objects.

O artigo de Tim é excelente, a única coisa que posso pensar é que ele presume que o repository está no formato LF, o que não é necessariamente verdade, especialmente para projetos somente do Windows.

Comparar o artigo de Tim com a resposta mais votada até hoje por jmlane mostra concordância perfeita sobre as configurações verdadeiras e de input e desacordo sobre a configuração falsa.

A melhor explicação de como funciona o core.autocrlf é encontrada na página do manual gitattributes , na seção de atributos text .

É assim que o core.autocrlf parece funcionar atualmente (ou pelo menos desde a v1.7.2 pelo que estou ciente):

  • core.autocrlf = true
    1. Os arquivos de texto retirados do repository que possuem apenas caracteres LF são normalizados para o CRLF na sua tree de trabalho; arquivos que contêm CRLF no repository não serão tocados
    2. Arquivos de texto que possuem apenas caracteres LF no repository são normalizados de CRLF para LF quando confirmados no repository. Arquivos que contêm CRLF no repository serão confirmados intocados.
  • core.autocrlf = input
    1. Os arquivos de texto retirados do repository manterão os caracteres EOL originais em sua tree de trabalho.
    2. Arquivos de texto em sua tree de trabalho com caracteres CRLF são normalizados para LF quando confirmados no repository.
  • core.autocrlf = false
    1. core.eol dita os caracteres EOL nos arquivos de texto da sua tree de trabalho.
    2. core.eol = native por padrão, o que significa que as core.eol = native Windows são CRLF e * nix As EOLs são LF em trees em funcionamento.
    3. gitattributes configurações do gitattributes repository determinam a normalização do caractere EOL para confirmações no repository (o padrão é a normalização para caracteres LF ).

Apenas recentemente pesquisei esse problema e também acho que a situação é muito complicada. A configuração core.eol definitivamente ajudou a esclarecer como os caracteres EOL são manipulados pelo git.

A questão das EOLs em projetos de plataformas mistas tem tornado minha vida miserável por um longo tempo. Os problemas geralmente surgem quando já existem arquivos com EOLs diferentes e mistos no repo. Isso significa que:

  1. O repository pode ter arquivos diferentes com diferentes EOLs
  2. Alguns arquivos no repository podem ter misturado EOL, por exemplo, uma combinação de CRLF e LF no mesmo arquivo.

Como isso acontece não é o problema aqui, mas acontece.

Eu executei alguns testes de conversão no Windows para os vários modos e suas combinações.
Aqui está o que eu tenho, em uma tabela ligeiramente modificada:

                  |  Conversão resultante quando |  Conversão resultante quando 
                  |  comprometendo arquivos com vários |  check out de repo - 
                  |  EOLs INTO repo e |  com arquivos mistos e
                  |  valor de core.autocrlf: |  valor de core.autocrlf:           
 -------------------------------------------------- ------------------------------
 Arquivo |  verdadeiro |  input |  falso |  verdadeiro |  input |  falso
 -------------------------------------------------- ------------------------------
 Windows-CRLF |  CRLF -> LF |  CRLF -> LF |  como está |  como está |  como está |  como é
 Unix -LF |  como está |  como está |  como está |  LF -> CRLF |  como está |  como é
 Mac -CR |  como está |  como está |  como está |  como está |  como está |  como é
 CRLF + LF Misto |  como está |  como está |  como está |  como está |  como está |  como é
 Misto-CRLF + LF + CR |  como está |  como está |  como está |  como está |  como está |  como é

Como você pode ver, existem 2 casos quando a conversão acontece no commit (3 colunas à esquerda). No restante dos casos, os arquivos são confirmados como estão.

No checkout (3 colunas à direita), há apenas 1 caso em que a conversão acontece quando:

  1. core.autocrlf é true e
  2. o arquivo no repository tem o LF EOL.

O mais surpreendente para mim, e eu suspeito, a causa de muitos problemas de EOL é que não há nenhuma configuração na qual o EOL misturado como CRLF + LF é normalizado.

Note também que os “velhos” Mac EOLs de CR também nunca são convertidos.
Isso significa que, se um script de conversão EOL mal escrito tentar converter um arquivo final misto com CRLF s + LF s, convertendo LF s em CRLF s, ele deixará o arquivo em um modo misto com CR s “solitários” CRLF foi convertido em CRCRLF .
O Git não irá converter nada, mesmo no modo true , e a destruição do EOL continua. Isso realmente aconteceu comigo e bagunçou meus arquivos muito mal, já que alguns editores e compiladores (por exemplo, VS2010) não gostam de EOLs de Mac.

Eu acho que a única maneira de realmente lidar com esses problemas é ocasionalmente normalizar todo o repository, verificando todos os arquivos na input ou no modo false , executando uma normalização adequada e reconfigurando os arquivos alterados (se houver). No Windows, presumivelmente, continue trabalhando com o core.autocrlf true .

As coisas estão prestes a mudar na frente do “eol conversion”, com o próximo Git 1.7.2 :

Uma nova configuração core.eol está sendo adicionada / evoluída :

Este é um substituto para o ‘Adicionar’ core.eol ‘config variable’ commit que está atualmente em pu (o último da minha série).
Em vez de sugerir que ” core.autocrlf=true ” é um substituto para ” * text=auto “, torna explícito o fato de que autocrlf é apenas para usuários que desejam trabalhar com CRLFs em seu diretório de trabalho em um repository que não o faz tem a normalização do arquivo de texto .
Quando ativado, “core.eol” é ignorado.

Introduzir uma nova variável de configuração, ” core.eol “, que permite ao usuário definir quais terminações de linha usar para arquivos normalizados de fim de linha no diretório de trabalho.
O padrão é ” native “, o que significa CRLF no Windows e LF em qualquer outro lugar. Note que ” core.autocrlf ” substitui o core.eol .
Isso significa que:

 [core] autocrlf = true 

coloca o CRLFs no diretório de trabalho, mesmo se o core.eol estiver definido como ” lf “.

 core.eol: 

Define o tipo de finalização de linha a ser usado no diretório de trabalho para arquivos que possuem a propriedade de text configurada.
As alternativas são ‘lf’, ‘crlf’ e ‘native’, que usam a terminação da linha nativa da plataforma.
O valor padrão é native .


Outras evoluções estão sendo consideradas :

Para o 1.8, eu consideraria fazer o core.autocrlf apenas ativar a normalização e deixar a decisão final da linha de diretório de trabalho para core.eol, mas isso quebrará as configurações das pessoas.


git 2.8 (março de 2016) melhora a forma como o core.autocrlf influencia o eol:

Veja commit 817a0c7 (23 Feb 2016), commit 6e336a5 , commit df747b8 , commit df747b8 (10 Feb 2016), commit df747b8 , commit df747b8 (10 Feb 2016), e commit 4b4024f , commit bb211b4 , commit 92cce13 , commit 320d39c , commit 4b4024f , commit bb211b4 , commit 92cce13 , commit 320d39c (05 Feb 2016) por Torsten Bögershausen ( tboegi ) .
(Mesclado por Junio ​​C Hamano – gitster – em commit c6b94eb , 26 de fevereiro de 2016)

convert.c : refactor crlf_action

Refatorar a determinação e uso de crlf_action .
Hoje, quando nenhum atributo ” crlf ” é definido em um arquivo, o crlf_action é definido como CRLF_GUESS . Use CRLF_UNDEFINED e procure por ” text ” ou ” eol ” como antes.

Substitua o uso antigo de CRLF_GUESS :

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

Faça mais claro, o que é o que, definindo:

 - 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 acrescenta nos comentários :

todas essas traduções (qualquer conversão EOL de eol= ou autocrlf e filtros ” clean “) são executadas quando os arquivos são movidos de tree de trabalho para índice , ou seja, durante git add vez de no tempo de git commit .
(Observe que git commit -a ou --only ou --only adicionam arquivos ao índice naquele momento.)

Para mais sobre isso, veja ” Qual é a diferença entre autocrlf e eol “.

core.autocrlf valor core.autocrlf não depende do tipo de SO, mas no valor padrão do Windows é true e para o Linux – input . Eu explorei 3 valores possíveis para casos de confirmação e checkout e esta é a tabela resultante:

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

Aqui está o meu entendimento até agora, no caso de ajudar alguém.

core.autocrlf=true e core.safecrlf = true

Você tem um repository onde todos os finais de linha são os mesmos , mas você trabalha em diferentes plataformas. O Git garantirá que os finais de suas linhas sejam convertidos para o padrão da sua plataforma. Por que isso importa? Vamos dizer que você crie um novo arquivo. O editor de texto em sua plataforma usará seus finais de linha padrão. Quando você faz check-in, se você não tiver o core.autocrlf configurado como true, você introduziu uma inconsistência de término de linha para alguém em uma plataforma que usa como padrão uma terminação de linha diferente. Eu sempre defino safecrlf também porque gostaria de saber que a operação crlf é reversível. Com essas duas configurações, o git está modificando seus arquivos, mas verifica se as modificações são reversíveis .

core.autocrlf=false

Você tem um repository que já tem finais de linha mistos verificados e corrigir os finais de linha incorretos pode quebrar outras coisas. É melhor não dizer ao git para converter as terminações de linha neste caso, porque isso irá exacerbar o problema que foi projetado para resolver – tornando os diffs mais fáceis de ler e mesclando menos dolorosos. Com esta configuração, o git não modifica seus arquivos .

core.autocrlf=input

Eu não uso isso porque a razão para isso é cobrir um caso de uso em que você criou um arquivo que possui terminações de linha CRLF em uma plataforma que padroniza os terminais de linha LF. Eu prefiro fazer meu editor de texto sempre salvar novos arquivos com os padrões de fim de linha da plataforma.

Fez alguns testes tanto no linux quanto no windows. Eu uso um arquivo de teste contendo linhas que terminam em LF e também linhas que terminam em CRLF.
O arquivo é confirmado, removido e, em seguida, retirado. O valor de core.autocrlf é definido antes do commit e também antes do checkout. O resultado está abaixo.

 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 

Não, a resposta @jmlane está errada.

Para Checkin (git add, git commit) :

  1. se a propriedade text for Set, Set value to 'auto' , a conversão acontece enen o arquivo foi confirmado com ‘CRLF’
  2. se a propriedade text for Unset : nada acontece, enen for Checkout
  3. Se a propriedade de text Unspecified for Unspecified , a conversão dependerá de core.autocrlf
    1. se autocrlf = input or autocrlf = true , a conversão só acontece quando o arquivo no repository é ‘LF’, se tiver sido ‘CRLF’, nada acontecerá.
    2. se autocrlf = false , nada acontece

Para o Checkout :

  1. Se a propriedade text for Unset : nada acontece.
  2. Se a propriedade text for Set, Set value to 'auto : depende de core.autocrlf , core.eol .
    1. core.autocrlf = input: nada acontece
    2. core.autocrlf = true: a conversão só acontece quando o arquivo no repository é ‘LF’, ‘LF’ -> ‘CRLF’
    3. core.autocrlf = false: a conversão só acontece quando o arquivo no repository é ‘LF’, ‘LF’ -> core.eol
  3. Se a propriedade text for Unspecified , isso depende do core.autocrlf .
    1. o mesmo que 2.1
    2. o mesmo que 2.2
    3. Nada, nada acontece, o core.eol não é eficaz quando a propriedade text é Unspecified

Comportamento Padrão

Portanto, o comportamento Padrão é a propriedade text is Unspecified e core.autocrlf = false :

  1. para check-in, nada acontece
  2. para checkout, nada acontece

Conclusões

  1. se a propriedade de text estiver definida, o comportamento de check-in depende de si próprio, não de autocrlf
  2. autocrlf ou core.eol é para o comportamento de checkout e autocrlf> core.eol