Forçar LF eol no repositório git e na cópia de trabalho

170

Eu tenho um repositório git hospedado no github. Muitos dos arquivos foram desenvolvidos inicialmente no Windows e eu não tomei muito cuidado com as terminações de linha. Quando realizei a confirmação inicial, também não havia nenhuma configuração git para impor finais de linha corretos. O resultado é que eu tenho vários arquivos com terminações de linha CRLF no meu repositório do github.

Agora estou desenvolvendo parcialmente no Linux e gostaria de limpar os finais de linha. Como garantir que os arquivos sejam armazenados corretamente com o LF no github e tenham o LF na minha cópia de trabalho?

Eu configurei um .gitattributesarquivo contendo text eol=LF; isso está correto? Com isso comprometido e empurrado, posso apenas reposicionar rmmeu local e clonar novamente no github para obter o efeito desejado?

Chowlett
fonte
1
possível duplicata de git substituindo LF com CRLF
preguiçoso Badger
Nenhuma delas é exatamente o que estou perguntando. Sou o único desenvolvedor e estou disposto a configurar todas as minhas máquinas da mesma forma. Eu tenho um repositório existente com alguns arquivos CRLF já confirmados e alguns clones em máquinas diferentes. Como posso atualizar o repositório e cada cópia de trabalho, para que haja LF em todos os lugares?
Chowlett
Você já viu este guia do Github?
Andy

Respostas:

237

Sem um pouco de informação sobre quais arquivos estão no seu repositório (código fonte puro, imagens, executáveis, ...), é um pouco difícil responder à pergunta :)

Além disso, considerarei que você deseja padronizar o LF como finais de linha no seu diretório de trabalho, porque deseja garantir que os arquivos de texto tenham finais de linha LF no seu repositório .git, independentemente de trabalhar no Windows ou Linux . Realmente melhor prevenir do que remediar ....

No entanto, há uma alternativa melhor: Beneficie-se das terminações da linha LF na sua área de trabalho Linux, das terminações da linha CRLF na sua extremidade da linha de trabalho do Windows E LF no seu repositório.

Como você está trabalhando parcialmente no Linux e no Windows, verifique se core.eolestá definido como nativee core.autocrlfestá definido como true.

Em seguida, substitua o conteúdo do seu .gitattributesarquivo pelo seguinte

* text=auto

Isso permitirá que o Git lide com a conversão de terminações de linha automática para você, em confirmações e check-outs. Os arquivos binários não serão alterados, os arquivos detectados como arquivos de texto verão as terminações das linhas convertidas em tempo real.

No entanto, como você conhece o conteúdo do seu repositório, você pode ajudar o Git e ajudá-lo a detectar arquivos de texto de arquivos binários.

Desde que você trabalhe em um projeto de processamento de imagem baseado em C, substitua o conteúdo do seu .gitattributesarquivo pelo seguinte

* text=auto
*.txt text
*.c text
*.h text
*.jpg binary

Isso garantirá que os arquivos cuja extensão seja c, h ou txt sejam armazenados com finais de linha LF no seu repositório e terão finais de linha nativos no diretório de trabalho. Arquivos JPEG não serão tocados. Todos os outros se beneficiarão da mesma filtragem automagica, como visto acima.

Para obter uma compreensão mais profunda dos detalhes internos de tudo isso, sugiro que você mergulhe neste post muito bom "Cuidado com o fim da sua linha", de Tim Clem, um Githubber.

Como um exemplo do mundo real, você também pode dar uma olhada nesse commit, onde essas alterações em um .gitattributesarquivo são demonstradas.

ATUALIZAÇÃO para a resposta considerando o seguinte comentário

Na verdade, eu não quero CRLF nos meus diretórios do Windows, porque meu ambiente Linux é realmente um VirtualBox compartilhando o diretório do Windows

Faz sentido. Obrigado pelo esclarecimento. Nesse contexto específico, o .gitattributesarquivo por si só não será suficiente.

Execute os seguintes comandos no seu repositório

$ git config core.eol lf
$ git config core.autocrlf input

Como seu repositório é compartilhado entre o ambiente Linux e Windows, isso atualizará o arquivo de configuração local para ambos os ambientes. core.eolgarantirá que os arquivos de texto tenham finais de linha LF nos caixas. core.autocrlfgarantirá que a CRLF em potencial nos arquivos de texto (resultantes de uma operação de copiar / colar, por exemplo) seja convertida em LF no seu repositório.

Opcionalmente, você pode ajudar o Git a distinguir o que é um arquivo de texto criando um .gitattributesarquivo que contenha algo semelhante ao seguinte:

# Autodetect text files
* text=auto

# ...Unless the name matches the following
# overriding patterns

# Definitively text files 
*.txt text
*.c text
*.h text

# Ensure those won't be messed up with
*.jpg binary
*.data binary

Se você decidiu criar um .gitattributesarquivo, confirme-o .

Por fim, certifique-se de git statusmencionar "nada a confirmar (diretório de trabalho limpo)" e execute a seguinte operação

$ git checkout-index --force --all

Isso recriará seus arquivos em seu diretório de trabalho, levando em consideração suas alterações de configuração e o .gitattributesarquivo e substituindo qualquer potencial CRLF negligenciado em seus arquivos de texto.

Uma vez feito isso, todos os arquivos de texto em seu diretório de trabalho git statusexibem terminações de linha LF e ainda devem considerar a área de trabalho limpa.

nulltoken
fonte
34
Na verdade, não quero CRLF nos meus diretórios do Windows, porque meu ambiente Linux é na verdade um VirtualBox compartilhando o diretório do Windows; e enquanto o Notepad ++ etc. pode lidar apenas com LF no Windows, vifica menos satisfeito com o CRLF. Eu só quero alterá-lo para que core.autocrlfseja false(ou input)?
Chowlett #
5
Excelente resposta. Uma observação rápida para qualquer pessoa que use essa configuração: A linha "* text = auto" deve ser a primeira linha do arquivo .gitattributes para que as linhas subseqüentes possam substituir essa configuração.
Ari Patrick
9
@CMCDragonkai Dependendo do seu shell, git checkout-index --force --allpode funcionar melhor. O segundo ponto parece um pouco fora do tópico em relação à pergunta original. Que tal fazer uma pergunta dedicada?
nulltoken
8
Não entendo por que .gitattributes não pode lidar com o caso de compartilhar uma cópia de trabalho entre Linux e Windows. Não podemos definir texte eol=lfobter o mesmo resultado descrito em sua resposta por meio de core.eole core.autocrlf?
DanielSank
10
git checkout-index --force --allnão faz nada por mim. O que funciona é a lista de comandos nas instruções do GitHub para lidar com esse problema.
Roman Starkov
127

A partir do git 2.10 (lançado em 09/09/2016), não é necessário enumerar cada arquivo de texto separadamente. O Git 2.10 corrigiu o comportamento de text = auto junto com eol = lf . Fonte .

.gitattributes arquivo na raiz do seu repositório git:

* text=auto eol=lf

Adicione e confirme.

Depois, você pode seguir as etapas e todos os arquivos estão normalizados agora:

git rm --cached -r .  # Remove every file from git's index.
git reset --hard      # Rewrite git's index to pick up all the new line endings.

Fonte: Resposta de kenorb .

koppor
fonte
7
O Git 2.10 foi lançado em 3 de setembro de 2016.
stil
Eu executei isso e ele emparelhava todos os meus arquivos não-texto
Anthony
Você pode definir explicitamente o modo binário para determinados arquivos. - Eu me pergunto por que a detecção automática está (ainda ?!) danificada em alguns arquivos
koppor
Essa deve ser a resposta aceita.
CletusW 07/07
25

Para forçar terminações de linha LF para todos os arquivos de texto, você pode criar um .gitattributesarquivo no nível superior do seu repositório com as seguintes linhas (altere conforme desejado):

# Ensure all C and PHP files use LF.
*.c         eol=lf
*.php       eol=lf

que garante que todos os arquivos que o Git considera como arquivos de texto tenham LFfinalizações de linha normalizadas ( ) no repositório (normalmente a core.eolconfiguração controla qual você possui por padrão).

Com base nas novas configurações de atributo, todos os arquivos de texto que contêm CRLFs devem ser normalizados pelo Git. Se isso não acontecer automaticamente, você poderá atualizar um repositório manualmente após alterar as terminações de linha, para verificar novamente e confirmar o diretório de trabalho seguindo as seguintes etapas (dado diretório de trabalho limpo):

$ echo "* text=auto" >> .gitattributes
$ rm .git/index     # Remove the index to force Git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

ou conforme os documentos do GitHub :

git add . -u
git commit -m "Saving files before refreshing line endings"
git rm --cached -r . # Remove every file from Git's index.
git reset --hard # Rewrite the Git index to pick up all the new line endings.
git add . # Add all your changed files back, and prepare them for a commit.
git commit -m "Normalize all the line endings" # Commit the changes to your repository.

Veja também: @Charles Bailey post .

Além disso, se você deseja excluir qualquer arquivo para não ser tratado como texto, desative o atributo de texto, por exemplo,

manual.pdf      -text

Ou marque-o explicitamente como binário:

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Para ver um arquivo de normalização git mais avançado, verifique .gitattributesno núcleo do Drupal :

# Drupal git normalization
# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# @see https://www.drupal.org/node/1542048

# Normally these settings would be done with macro attributes for improved
# readability and easier maintenance. However macros can only be defined at the
# repository root directory. Drupal avoids making any assumptions about where it
# is installed.

# Define text file attributes.
# - Treat them as text.
# - Ensure no CRLF line-endings, neither on checkout nor on checkin.
# - Detect whitespace errors.
#   - Exposed by default in `git diff --color` on the CLI.
#   - Validate with `git diff --check`.
#   - Deny applying with `git apply --whitespace=error-all`.
#   - Fix automatically with `git apply --whitespace=fix`.

*.config  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.css     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.dist    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.engine  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.html    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html
*.inc     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.js      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.json    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.lock    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.map     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.module  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.php     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.po      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.script  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.sh      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.sql     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.svg     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.theme   text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.twig    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.txt     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.xml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.yml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

# Define binary file attributes.
# - Do not treat them as text.
# - Include binary diff in patches instead of "binary files differ."
*.eot     -text diff
*.exe     -text diff
*.gif     -text diff
*.gz      -text diff
*.ico     -text diff
*.jpeg    -text diff
*.jpg     -text diff
*.otf     -text diff
*.phar    -text diff
*.png     -text diff
*.svgz    -text diff
*.ttf     -text diff
*.woff    -text diff
*.woff2   -text diff

Veja também:

kenorb
fonte
2
1. text=autoé enganoso. Você não pode usar text=autoe eoljuntos. A configuração eoldesativa a detecção automática de arquivos de texto. É por isso que você precisa especificar todos esses tipos de arquivos. Se autoestivesse ativado, você não precisaria de tudo isso. 2. Você não precisa texte eol=lf. eol=lfefetivamente define text.
Ben
2
Segundo o que o @Ben disse, essa configuração está incorreta e perigosa se você não marcar explicitamente todos os arquivos binários.
Michael R
1
Eu li que * text=auto eol=lfo primeiro text=autoé substituído por eol=lf. Onde você encontrou esse recurso? Aqui está a minha fonte: stackoverflow.com/questions/29435156/...
CMCDragonkai
Removido * text=auto eol=lfdo exemplo, pois também foi removido do Drupal. Considere remover os comentários também.
Kenorb
4
É importante observar que o que o @Ben disse não é mais verdade e sempre foi um bug - não um comportamento pretendido.
Semmel