Tentando consertar terminações de linha com git filter-branch, mas sem sorte

Eu fui mordido pelo problema de fim de linha do Windows / Linux com o git. Parece, via GitHub, MSysGit, e outras fonts, que a melhor solução é ter seus repositorys locais configurados para usar terminais de linha no estilo linux, mas configure core.autocrlf para true . Infelizmente, eu não fiz isso cedo o suficiente, então agora toda vez que eu puxo as mudanças, as terminações da linha são feitas.

Eu pensei que tinha encontrado uma resposta aqui, mas não consigo fazer isso funcionar para mim. Meu conhecimento de linha de comando do Linux é limitado na melhor das hipóteses, então eu nem tenho certeza do que a linha “xargs fromdos” faz em seu script. Eu continuo recebendo mensagens sobre nenhum tal arquivo ou diretório existente, e quando eu consigo apontar para um diretório existente, ele me diz que não tenho permissions.

Eu tentei isso com MSysGit no Windows e através do terminal do Mac OS X.

A documentação do git para gitattributes agora documenta outra abordagem para “consertar” ou normalizar todos os finais de linha em seu projeto. Aqui está a essência disso:

 $ echo "* text=auto" >.gitattributes $ git add --renormalize . $ git status # Show files that will be normalized $ git commit -m "Introduce end-of-line normalization" 

Se algum arquivo que não deve ser normalizado aparecer no status git, desative seu atributo de texto antes de executar git add -u.

manual.pdf -text

Por outro lado, os arquivos de texto que o git não detecta podem ter a normalização ativada manualmente.

weirdchars.txt text

Isso aproveita um novo sinalizador --renormalize adicionado no git v2.16.0, lançado em janeiro de 2018. Para versões mais antigas do git, há mais algumas etapas:

 $ 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" 

A maneira mais fácil de corrigir isso é fazer um commit que conserte todos os finais de linha. Supondo que você não tenha arquivos modificados, faça o seguinte.

 # From the root of your repository remove everything from the index git rm --cached -r . # Change the autocrlf setting of the repository (you may want # to use true on windows): git config core.autocrlf input # Re-add all the deleted files to the index # (You should get lots of messages like: # warning: CRLF will be replaced by LF in .) git diff --cached --name-only -z | xargs -0 git add # Commit git commit -m "Fixed crlf issue" # If you're doing this on a Unix/Mac OSX clone then optionally remove # the working tree and re-check everything out with the correct line endings. git ls-files -z | xargs -0 rm git checkout . 

Meu procedimento para lidar com os finais de linha é o seguinte (teste de batalha em muitos repos):

Ao criar um novo repo:

  • Coloque .gitattributes no primeiro commit junto com outros arquivos típicos como .gitignore e README.md

Ao lidar com um repo existente:

  • Crie / modifique .gitattributes adequadamente
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n ( --no-verify é para pular ganchos de pré-commit)
    • Eu tenho que fazer isso com bastante freqüência que eu defini como um alias alias fixCRLF="..."
  • repita o comando anterior
    • sim, é voodoo, mas geralmente eu tenho que executar o comando duas vezes, a primeira vez que normaliza alguns arquivos, segunda vez ainda mais arquivos. Geralmente é melhor repetir até que nenhum novo commit seja criado 🙂
  • ir e voltar entre o antigo (pouco antes da normalização) e o novo ramo algumas vezes. Depois de alternar o branch, às vezes o git encontrará ainda mais arquivos que precisam ser renormalizados!

Em .gitattributes Declaro todos os arquivos de texto explicitamente como tendo LF EOL, pois geralmente o Windows é compatível com LF, enquanto o não-Windows não é compatível com CRLF (mesmo muitas ferramentas de linha de comando do nodejs assumem o LF e podem alterar o EOL dos arquivos) .

Conteúdo de .gitattributes

Meus .gitattributes geralmente se parecem com:

 *.html eol=lf *.js eol=lf *.json eol=lf *.less eol=lf *.md eol=lf *.svg eol=lf *.xml eol=lf 

Para descobrir quais extensões distintas são rastreadas pelo git no repository atual, veja aqui

Problemas após normalização

Uma vez feito isso, há mais uma ressalva comum.

Digamos que seu master já esteja atualizado e normalizado e, em seguida, você finalize o outdated-branch . Muitas vezes, logo após o check out dessa ramificação, o git marca muitos arquivos modificados.

A solução é fazer um commit falso ( git add -A . && git commit -m 'fake commit' ) e depois git rebase master . Após o rebase, o commit falso deve desaparecer.

 git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos 

Explicação:

  • git status --short

    Isso exibe cada linha que o git está e não está ciente. Arquivos que não estão sob controle git são marcados no começo da linha com um ‘?’. Arquivos que são modificados são marcados com um M.

  • grep "^ *M"

    Isso filtra apenas os arquivos que foram modificados.

  • awk '{print $2}'

    Isso mostra apenas o nome do arquivo sem nenhum marcador.

  • xargs fromdos

    Isso pega os nomes de arquivos do comando anterior e os executa através do utilitário ‘fromdos’ para converter os fins de linha.

O “| xargs fromdos” lê a partir da input padrão (os arquivos find achados) e os usa como argumentos para o comando fromdos , que converte os finais de linha. (É padrão de fromdos nesses ambientes? Eu estou acostumado a dos2unix). Note que você pode evitar o uso de xargs (especialmente útil se você tiver arquivos suficientes que a lista de argumentos é muito longa para xargs):

 find  -exec fromdos '{}' \; 

ou

 find  | while read file; do fromdos $file; done 

Eu não estou totalmente certo sobre suas mensagens de erro. Eu testei com sucesso este método. Qual programa está produzindo cada um? Quais arquivos / diretórios você não tem permissão para? No entanto, aqui está uma tentativa de adivinhar qual poderia ser:

Uma maneira fácil de obter um erro ‘arquivo não encontrado’ para o script é usando um caminho relativo – use um caminho absoluto. Da mesma forma, você pode obter um erro de permissão se não tiver tornado seu script executável (chmod + x).

Adicione comentários e eu vou tentar ajudá-lo a trabalhar!

Ok … sob cygwin não temos fromdos facilmente disponíveis, e awk substeb explode na sua cara, se você tem algum espaço em caminhos para arquivos modificados (o que tínhamos), então eu tive que fazer isso de forma um pouco diferente:

 git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix 

elogios para @lloyd para a maior parte desta solução

Aqui está como eu consertei todos os finais de linha em todo o histórico usando git filter-branch . O caractere ^M precisa ser typescript usando CTRL-V + CTRL-M . Eu usei o dos2unix para converter os arquivos, pois isso ignora automaticamente os arquivos binários.

 $ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"' 

Siga estas etapas se nenhuma das outras respostas funcionar para você:

  1. Se você estiver no Windows, faça o git config --global core.autocrlf true ; se você estiver no Unix, faça o git config core.autocrlf input
  2. Execute git rm --cached -r .
  3. Exclua o arquivo .gitattributes
  4. Executar git add -A
  5. Executar git reset --hard

Então o seu local deve estar limpo agora.