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

220

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

Esta é a minha compreensão do que li:

Os clientes Unix e Mac OSX (pré-OSX usam CR) usam terminações de linha LF.
Os clientes Windows usam terminações de linha CRLF.

Quando core.autocrlf é definido como true no cliente, o repositório git sempre armazena arquivos no formato de final de linha LF e os finais de linha em arquivos no cliente são convertidos para frente e para trás no check-out / commit para clientes (ou seja, Windows) que usam não -LF terminações de linha, independentemente do formato dos arquivos de finalização de linha no cliente (isso não concorda 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 final de linha.

Minhas perguntas são:

  1. Quais devem ser os pontos de interrogação?
  2. Essa matriz está correta para os "pontos de interrogação"?

Vou atualizar os pontos de interrogação das respostas à medida que o consenso parece ser formado.

                       valor core.autocrlf
            entrada verdadeira false
-------------------------------------------------- --------
confirmar | converter? ?
novo | para LF (converter para LF?) (sem conversão?)

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

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

Na verdade, não estou 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 vinculado por JJD nos comentários, modifiquei alguns dos valores nos valores "desconhecidos" na tabela acima, além de alterar "checkout existente | true para converter para CRLF em vez de converter para cliente ". Aqui estão as definições que ele fornece, que são mais claras do que qualquer outra coisa que já vi em outros lugares:

core.autocrlf = false

Esse é o padrão, mas a maioria das pessoas é incentivada a mudar isso imediatamente. O resultado do uso de false é que o Git nunca mexe com as terminações de linha no seu arquivo. Você pode fazer check-in de arquivos com LF ou CRLF ou CR ou alguma mistura aleatória desses três e o Git não se importa. Isso pode dificultar a leitura do diffs e mesclar mais difícil. A maioria das pessoas que trabalha no mundo Unix / Linux usa esse valor porque não possui problemas de CRLF e não precisa que o Git faça um trabalho extra sempre que os arquivos forem gravados no banco de dados do objeto 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 pelo LF ao gravar esse arquivo no banco de dados de objetos e transformar todo o LF novamente no CRLF ao gravar no diretório de trabalho. Essa é a configuração recomendada no Windows, pois garante que seu repositório possa ser usado em outras plataformas, mantendo o CRLF em seu diretório de trabalho.

core.autocrlf = input

Isso significa que o Git processará todos os arquivos de texto e verifique se o CRLF é substituído pelo LF ao gravar esse arquivo no banco de dados do objeto. No entanto, não fará o contrário. Quando você lê os arquivos novamente no banco de dados do objeto 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 CRLFs sejam gravados no repositório. A idéia é que, se você colasse o código de um navegador da Web e colocasse CRLFs acidentalmente em um de seus arquivos, o Git garantiria que eles fossem substituídos por LFs quando você escrevesse no banco de dados de objetos.

O artigo de Tim é excelente, a única coisa que consigo pensar é que ele assume que o repositório está no formato LF, o que não é necessariamente verdadeiro, especialmente para projetos somente do Windows.

Comparar o artigo de Tim com a resposta mais votada até o momento por jmlane mostra concordância perfeita com as configurações true e input e discordância com a false false.

Michael Maddox
fonte
7
Manter- autocrlfse falso parece muito mais fácil;) stackoverflow.com/questions/2333424/…
VonC
@VonC: Eu li isso e acho que entendo, mas não necessariamente faço a escolha. Eu trabalho com repositórios git que não controla quem exige que eu defina o valor de uma certa maneira.
Michael Maddox
5
Não seria bom se o Windows também normalizasse para LF? O Mac costumava ser CR (anterior v10), mas agora é normalizado para LF.
Brett Ryan
3
Preciso adicionar um link para o excelente artigo de Timothy Clem - leia toda a Mind the End of Your Line .
JJD
1
Cenário: Sou desenvolvedor de Linux / Windows dividido. Eu só uso editores de texto que podem reconhecer os dois tipos de terminações de linha (IE. Vim, eclipse). Eu só preciso (quero) trabalhar com arquivos que terminam em LF. Atualmente, tenho core.autocrlf = input definido na minha configuração global do git. Eu estou pronto para ir? Eu terei algum conflito?
Chris

Respostas:

128

A melhor explicação de como core.autocrlffunciona é encontrada na página de manual gitattributes , na textseção de atributos.

É assim que core.autocrlfparece funcionar atualmente (ou pelo menos desde a v1.7.2 do que eu sei):

  • core.autocrlf = true
    1. Os arquivos de texto retirados do repositório que possuem apenas LFcaracteres são normalizados CRLFna sua árvore de trabalho; arquivos que contêm CRLFno repositório não serão tocados
    2. Os arquivos de texto que possuem apenas LFcaracteres no repositório são normalizados de CRLFpara LFquando confirmados no repositório. Os arquivos que contêm CRLFno repositório serão confirmados intocados.
  • core.autocrlf = input
    1. Os arquivos de texto retirados do repositório manterão os caracteres EOL originais em sua árvore de trabalho.
    2. Os arquivos de texto em sua árvore de trabalho com CRLFcaracteres são normalizados LFquando confirmados no repositório.
  • core.autocrlf = false
    1. core.eol determina caracteres EOL nos arquivos de texto da sua árvore de trabalho.
    2. core.eol = nativepor padrão, o que significa que as EOLs do Windows estão CRLFe * nix EOLs estão LFem árvores de trabalho.
    3. As gitattributesconfigurações do repositório determinam a normalização de caracteres EOL para confirmações no repositório (o padrão é normalização para LFcaracteres).

Pesquisei apenas recentemente esse problema e também acho a situação muito complicada. A core.eoldefinição definitivamente ajudou a esclarecer como os caracteres de fim de linha são tratados pelo git.

jmlane
fonte
3
para autocrlf = true não deve ser o seguinte? Os arquivos de texto que possuem apenas caracteres ERL CRLF no repositório são normalizados de CRLF para LF quando confirmados no repositório. Os arquivos que contêm LF no repositório serão confirmados intocados.
Piotr Lewandowski
2
Para mim, mesmo que autocrlf = false git estivesse convertendo o EOL em CRLF. Depois de ler esta resposta, percebi que meu arquivo .gitattribute tinha text = auto set, o que estava causando o problema.
irsis
1
Pois core.autocrlf = false, se eu não tenho um gitattributesarquivo, isso significa que não haverá normalização? Ou isso significa que usará a normalização padrão?
Chin
O .gitattributesarquivo não deve ter precedência sobre a core.autocrlfconfiguração?
Qwerty
63

A questão das EOLs em projetos de plataforma mista vem tornando minha vida miserável há muito tempo. Os problemas geralmente surgem quando já existem arquivos com diferentes e mistos EOLs no repo. Isso significa que:

  1. O repositório pode ter arquivos diferentes com diferentes EOLs
  2. Alguns arquivos no repositório podem ter EOL misto, por exemplo, uma combinação CRLFe LFno 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
                 | enviando arquivos com vários | check-out do repo -
                 | EOLs em operações compromissadas e | com arquivos mistos nele e
                 | valor core.autocrlf: | valor core.autocrlf:           
-------------------------------------------------- ------------------------------
Arquivo | verdadeiro entrada | falso | verdadeiro entrada | falso
-------------------------------------------------- ------------------------------
CRLF do Windows | LCRF -> LF | LCRF -> LF | como está | como está | como está | como é
Unix -LF | como está | como está | como está | LF -> LCRF | como está | como é
Mac -CR | como está | como está | como está | como está | como está | como é
LCRF misto + LF | como está | como está | como está | como está | como está | como é
LCRF misto + LF + CR | como está | como está | como está | como está | como está | como é

Como você pode ver, existem 2 casos em que a conversão ocorre 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 ocorre quando:

  1. core.autocrlfé true e
  2. o arquivo no repositório tem o LFEOL.

O mais surpreendente para mim, e suspeito, a causa de muitos problemas de EOL é que não há uma configuração na qual a EOL mista como CRLF+ LFseja normalizada.

Observe também que os EOLs Mac "antigos" de CRapenas nunca são convertidos.
Isso significa que, se um script de conversão EOL mal escrito tentar converter um arquivo final misto com CRLFs + LFs, apenas convertendo LFs para CRLFs, ele deixará o arquivo em um modo misto com "solitário" CRs para onde CRLFfoi convertido CRCRLF.
O Git não converterá nada, mesmo no truemodo, e a destruição do EOL continuará. Isso realmente aconteceu comigo e atrapalhou muito meus arquivos, pois alguns editores e compiladores (por exemplo, VS2010) não gostam de Mac EOLs.

Eu acho que a única maneira de realmente lidar com esses problemas é ocasionalmente normalizar todo o repositório, verificando todos os arquivos no modo inputou false, executando uma normalização adequada e confirmando novamente os arquivos alterados (se houver). No Windows, presumivelmente, retome o trabalho core.autocrlf true.

Adi Shavit
fonte
4
Excelente resposta, mas uma frase com a qual não concordo é No Windows, presumivelmente, retome o trabalhocore.autocrlf true . Pessoalmente, acredito que inputdeve ser usado sempre.
G. Demecki 12/01
39

As coisas estão prestes a mudar na frente da "conversão de eol", com o próximo Git 1.7.2 :

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

Esta é uma substituição para o core.eolcommit 'Adicionar " " variável de configuração "que está atualmente 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 seus diretórios de trabalho em um repositório que não possui normalização de arquivo de texto .
Quando está ativado, "core.eol" é ignorado.

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

[core]
  autocrlf = true

coloca CRLFs no diretório de trabalho, mesmo que core.eolesteja definido como " lf".

core.eol:

Define o tipo de final de linha a ser usado no diretório ativo para arquivos que possuem a textpropriedade definida.
As alternativas são 'lf', 'crlf' e 'native', que usa o final da linha nativa da plataforma.
O valor padrão é native.


Outras evoluções estão sendo consideradas :

Para 1.8, eu consideraria fazer core.autocrlfbasta ligar normalização e deixar a linha diretório de trabalho terminando decisão de core.eol, mas isso vai quebrar configurações das pessoas.


O git 2.8 (março de 2016) melhora a maneira como core.autocrlfinfluencia o eol:

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

convert.c: refatorar crlf_action

Refatorar a determinação e o uso de crlf_action.
Hoje, quando nenhum crlfatributo " " está definido em um arquivo, crlf_actionestá definido como CRLF_GUESS. Use em CRLF_UNDEFINEDvez disso e pesquise " text" ou " eol" como antes.

Substitua o CRLF_GUESSuso antigo :

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

Deixe mais claro, o que é o quê, 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 de EOL eol=ou autocrlfconfigurações e cleanfiltros " ") são executadas quando os arquivos passam da árvore de trabalho para o índice , ou seja, durante git adde não no git committempo.
(Observe que git commit -aou --onlyou --includeadicione arquivos ao índice naquele momento.)

Para mais informações, consulte " Qual é a diferença entre autocrlf e eol ".

VonC
fonte
18
Infelizmente, isso não adiciona clareza para mim. Parece que eles estão dizendo que há problemas com a implementação atual (não está claro quais são esses problemas) e estão aumentando a complexidade em um esforço para resolver esses problemas não especificados. Na minha opinião, a configuração core.autocrlf já é excessivamente complexa e sub-documentada e essa situação parece estar piorando. Mais uma vez obrigado pelo aviso.
Michael Maddox
1
Isso não parece uma solução satisfatória e parece ter os mesmos problemas que o core.autocrlf. Minha preferência seria se o git nunca modificasse nada automaticamente, mas alertaria o usuário que deseja adicionar ou confirmar as terminações de linha erradas. Portanto, você precisaria de uma opção de linha de comando para permitir que "git add" adicione as terminações de linha "erradas". (provavelmente git add é o lugar melhor para verificar isso do que git commit)
Donquixote
Isso forçaria o respectivo usuário a alterar as configurações do editor e realmente resolver o problema. Embora isso permita deixar as terminações de linha "erradas" para arquivos de terceiros ou que já estão verificados no repositório.
Donquixote
@donquixote novamente, eu concordo. Mas core.eoltrata-se de "modificar automaticamente" apenas o que você declara explicitamente em um .gitattributesarquivo. É diferente do core.autocrlfque se aplica a qualquer arquivo no repositório. É um processo declarativo.
VonC 20/09/14
1
@donquixote: Sei que isso é bastante antigo, mas só li seu comentário agora. De fato, todas essas traduções (qualquer conversão EOL de configurações eol = ou autocrlf e filtros "limpos") são executadas quando os arquivos passam da árvore de trabalho para o índice, ou seja, durante git adde não no git commitmomento. (Note-se que git commit -aou --onlyou --includefazer arquivos adicionar ao índice, nesse momento, no entanto.) Por que vale a pena, você e eu e Linus Torvalds todos odeiam a idéia de um VCS nunca modificar o que está sendo cometido. Mas não são todos aqueles usuários do Windows ... :-)
Torek
34

core.autocrlfO valor não depende do tipo de SO, mas o valor padrão do Windows é truee para Linux - input. Eu explorei 3 valores possíveis para casos de confirmação e verificação e esta é a tabela 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 ║
╚═══════════════╩══════════════╩══════════════╩══════════════╝
pratt
fonte
5
Resumo resumido em palavras: os arquivos CRsozinhos nunca são tocados. falsenunca toca nas terminações da linha. truesempre confirma como LFe verifica como CRLF. E inputsempre comete como LFe verifica como é.
Furkan Kambay
7

Aqui está o meu entendimento até agora, caso ajude alguém.

core.autocrlf=true e core.safecrlf = true

Você tem um repositório onde todas as terminações de linha são iguais , mas você trabalha em plataformas diferentes. O Git garantirá que as terminações de suas linhas sejam convertidas no padrão para sua plataforma. Por que isso importa? Digamos que você crie um novo arquivo. O editor de texto na sua plataforma usará suas terminações de linha padrão. Quando você faz o check-in, se você não tem core.autocrlf definido como true, introduziu uma inconsistência de final de linha para alguém em uma plataforma que usa como padrão um final de linha diferente. Também sempre defino safecrlf 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 repositório que já possui finais de linha misturados 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 nesse caso, porque isso exacerbará o problema que foi projetado para resolver - tornando as diferenças mais fáceis de ler e mesclando menos dolorosas. Com essa configuração, o git não modifica seus arquivos .

core.autocrlf=input

Não uso isso porque o motivo é para cobrir um caso de uso em que você criou um arquivo que possui terminações de linha CRLF em uma plataforma que usa como padrão as terminações de linha LF. Prefiro fazer meu editor de texto sempre salvar novos arquivos com os padrões de final de linha da plataforma.

Carl
fonte
3

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

Para Checkin (git add, git commit):

  1. se a textpropriedade for Set, Set value to 'auto', a conversão ocorre e o arquivo foi confirmado com 'CRLF'
  2. se textpropriedade for Unset: nada acontece, enen paraCheckout
  3. se a textpropriedade for Unspecified, a conversão depende decore.autocrlf
    1. se autocrlf = input or autocrlf = truea conversão ocorrer apenas quando o arquivo no repositório for 'LF', se tiver sido 'CRLF', nada acontecerá.
    2. se autocrlf = falsenada acontecer

Para Checkout:

  1. se textpropriedade for Unset: nada acontece.
  2. Se textpropriedade é Set, Set value to 'auto: depende core.autocrlf, core.eol.
    1. core.autocrlf = input: nada acontece
    2. core.autocrlf = true: a conversão ocorre apenas quando o arquivo no repositório é 'LF', 'LF' -> 'CRLF'
    3. core.autocrlf = false: a conversão só acontece quando o arquivo no repositório é 'LF', 'LF' -> core.eol
  3. se a textpropriedade é Unspecified, depende core.autocrlf.
    1. o mesmo que 2.1
    2. o mesmo que 2.2
    3. Nada, nada acontece, core.eol não é eficaz quando a textpropriedade éUnspecified

Comportamento padrão

Portanto, o comportamento padrão é textpropriedade is Unspecifiede core.autocrlf = false:

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

Conclusões

  1. se a textpropriedade estiver configurada, o comportamento do check-in depende de si mesmo, não do autocrlf
  2. autocrlf ou core.eol é para comportamento de saída e autocrlf> core.eol
ViciOs
fonte
2

Fiz alguns testes no linux e no windows. Eu uso um arquivo de teste contendo linhas que terminam em LF e também que terminam em CRLF.
O arquivo é confirmado, removido e retirado. O valor de core.autocrlf é definido antes da confirmação e também antes da finalização da compra. 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  
Luc Depoorter
fonte