Status do Git ignora terminações de linha / arquivos idênticos / ambiente windows e linux / dropbox / mled

112

Como eu faço

git status

ignorar diferenças de finalização de linha?

Informação de fundo:

Eu uso o Windows e o Linux aleatoriamente para trabalhar no projeto. O projeto está no Dropbox.

Eu descobri muito sobre como fazer git diff ignorar terminações de linha. Como eu uso o meld, o git diff abre o meld para cada arquivo. E o meld diz "arquivo idêntico".

Então, como faço para evitar isso. O Git deve abrir o meld apenas para arquivos alterados. E o git status não deve relatar os arquivos como alterados se apenas o final do arquivo for diferente.

EDITAR: Causa:

Isso aconteceu por causa desta configuração no Windows

core.autocrlf true

Portanto, verifiquei a cópia de trabalho no Linux e defini core.autocrlf como falso no Windows.

Ainda seria bom saber como fazer git status ignorar novas linhas diferentes.

Thorsten Niehues
fonte
3
Se você estiver compartilhando o arquivo usando dropbox em plataformas diferentes, isso acontecerá, a menos que você diga explicitamente ao git para tratar todos os arquivos como binários. A solução adequada é não usar a caixa de depósito para repositórios git
Petesh
lembre-se: stackoverflow.com/questions/2825428/… - isso pode ajudar um pouco
Petesh
Descobri como funciona bem com o Dropbox: definindo core.autocrlf false
Thorsten Niehues
3
O AFAIK dizendo ao git para tratar os arquivos como binários também tem o efeito colateral de alterar a maneira como diffs o arquivo. A solução adequada é dizer ao git para ignorar as terminações de linha. Duas das minhas coisas menos favoritas: lidar com problemas de finalização de linha e FUD sarcástico desnecessário sobre a maneira como as pessoas configuram seus
repositórios
Nossa, demorei um pouco para que esse problema core.autocrlfseja a causa raiz no Windows, mas também uma cura no Linux. O problema é que autocrlfé global no Windows e o repo não tem essa configuração .git/config. Ao executar um local, git config core.autocrlf trueeliminei as alterações espúrias na minha cópia de trabalho NTFS clonada no Windows, mas acessada no Linux. (agora há apenas alterações espúrias com links simbólicos - links simbólicos NTFS FUNCIONAM em montagens fuseblk, mas Git os vê como modificados ...)
Tomasz Gandor

Respostas:

103

Tente definir o valor core.autocrlf como este:

git config --global core.autocrlf true
Saša Šijak
fonte
7
@ThorstenNiehues Eu uso essa configuração em algum projeto de trabalho. No trabalho devo usar windows, home eu uso mac e linux. Antes eu tinha o mesmo problema que você, depois daquela configuração estava tudo ok.
Saša Šijak
1
Isso é estranho porque um check-out no Windows tem \ r \ n terminações de linha apenas no Linux \ n Você tem as duas cópias de trabalho no Dropbox (ou similar)?
Thorsten Niehues
1
@ThorstenNiehues Não, o repositório git está no github. Hmm, talvez o dropbox esteja de alguma forma bagunçando as terminações de linha quando sincroniza arquivos? Parece estranho usar dropbox para git. Tente usar o bitbucket (ele tem repositórios privados gratuitos), apenas faça um pequeno repo e teste em suas 2 máquinas com alguns pequenos arquivos de texto.
Saša Šijak
1
1. A cópia de trabalho e o repositório local estão no Dropbox (não preciso de um repositório público), essa é provavelmente a diferença
Thorsten Niehues
3
No Windows: core.autocrlf trueé uma configuração funcional no CygWin. core.safecrlf falseé uma configuração funcional em git bash ou mingw
DrumM
43

Em vez disso, use .gitattributes, com a seguinte configuração:

# Ignore all differences in line endings
*        -crlf

.gitattributes seriam encontrados no mesmo diretório que seu .gitconfig global. Se .gitattributes não existir, adicione-o a esse diretório. Depois de adicionar / alterar atributos .git, você terá que fazer uma reinicialização a frio do repositório para aplicar com êxito as alterações aos arquivos existentes.

Lixeiro
fonte
Funcionou para mim em um stream, mas quando tentei criá-lo em outro stream para o mesmo projeto, ainda mostra diferenças de Newline.
pfernandom
1
@pfernandom, você possivelmente tem vários atributos .git em seu projeto? Ele examinará primeiro a versão mais "local", portanto, se você tiver uma no diretório local onde os arquivos estão, ele a usará em todo o projeto.
Trashman
Ele precisa ter 8 espaços antes de -crlf?
Igonato
Não importa
Trashman
Isso faz mais do que simplesmente ignorar as terminações de linha de git status. Na verdade, ele muda a forma como os arquivos são inseridos no repositório. ref: git-scm.com/docs/gitattributes#_code_text_code
Vince
31

Essa resposta parece relevante, uma vez que o OP faz referência à necessidade de uma solução multi-SO. Este artigo de ajuda do Github detalha as abordagens disponíveis para lidar com terminações de linhas entre sistemas operacionais. Existem abordagens globais e por repo para gerenciar terminações de linha cross-os.

Abordagem global

Configure o tratamento de terminações de linha Git no Linux ou OS X:

git config --global core.autocrlf input

Configure o tratamento de terminações de linha Git no Windows:

git config --global core.autocrlf true

Abordagem por repo:

Na raiz do seu repo, crie um .gitattributesarquivo e defina as configurações de finalização de linha para seus arquivos de projeto, uma linha por vez no seguinte formato: path_regex line-ending-settingsonde line-ending-settingsé um dos seguintes:

  • texto
  • binário (arquivos para os quais o Git não deve modificar terminações de linha - pois isso pode fazer com que alguns tipos de imagens, como PNGs, não sejam renderizados em um navegador)

O textvalor pode ser configurado posteriormente para instruir o Git sobre como lidar com terminações de linha para arquivos correspondentes:

  • text - Altera terminações de linha para terminações de linha nativas do sistema operacional.
  • text eol=crlf- Converte terminações de linha CRLFem check-out.
  • text eol=lf- Converte terminações de linha LFem check-out.
  • text=auto - Padrão sensato que deixa o controle de linha a critério do Git.

Aqui está o conteúdo de um arquivo de amostra .gitattributes:

# Set the default behavior for all files.
* text=auto

# Normalized and converts to 
# native line endings on checkout.
*.c text
*.h text

# Convert to CRLF line endings on checkout.
*.sln text eol=crlf

# Convert to LF line endings on checkout.
*.sh text eol=lf

# Binary files.
*.png binary
*.jpg binary

Saiba mais sobre como atualizar seu repo após alterar as configurações de término de linha aqui . Tldr:

faça backup de seus arquivos com Git, exclua todos os arquivos em seu repositório (exceto o diretório .git) e restaure os arquivos de uma vez. Salve seus arquivos atuais no Git, para que nenhum de seu trabalho seja perdido.

git add . -u

git commit -m "Saving files before refreshing line endings"

Remova o índice e force o Git a examinar novamente o diretório de trabalho.

rm .git/index

Reescreva o índice Git para pegar todas as novas terminações de linha.

git reset

Mostra os arquivos normalizados reescritos.

Em alguns casos, isso é tudo o que precisa ser feito. Outros podem precisar completar as seguintes etapas adicionais:

git status

Adicione todos os seus arquivos alterados de volta e prepare-os para um commit. Esta é sua chance de inspecionar quais arquivos, se houver, não foram alterados.

git add -u

É perfeitamente seguro ver muitas mensagens aqui que dizem "aviso: CRLF será substituído por LF no arquivo."

Reescreva o arquivo .gitattributes.

git add .gitattributes

Envie as alterações para seu repositório.

git commit -m "Normalize all the line endings"

user4603841
fonte
18

Problema relacionado aos comandos git no sistema operacional Windows:

$ git add --all

aviso: LF será substituído por CRLF em ...

O arquivo terá suas terminações de linha originais em seu diretório de trabalho.

Resolução :

$ git config --global core.autocrlf false     
$ git add --all 

Nenhuma mensagem de aviso aparece.

Winstonhong
fonte
você deve fazer isso em todos os sistemas operacionais que estiver usando, ou seja: no Windows e no Linux. Lembre-se de que cada sistema operacional tem seu próprio arquivo global .git / config, portanto, você precisa tornar essas configurações semelhantes. É por isso que @Thorsten você estava tendo problemas. Mas eu defino o sinalizador como verdadeiro em vez de falso.
Emmanuel Mahuni
Esta solução também funciona em linux (a resposta de @ SašaŠijak não funcionou para mim)
juliocesar
4

Criei um script para ignorar diferenças nas terminações de linha:

Ele exibirá os arquivos que não foram adicionados à lista de confirmação e foram modificados (após ignorar as diferenças nos finais de linha). Você pode adicionar o argumento "add" para adicionar esses arquivos ao seu commit.

#!/usr/bin/perl

# Usage: ./gitdiff.pl [add]
#    add : add modified files to git

use warnings;
use strict;

my ($auto_add) = @ARGV;
if(!defined $auto_add) {
    $auto_add = "";
}

my @mods = `git status --porcelain 2>/dev/null | grep '^ M ' | cut -c4-`;
chomp(@mods);
for my $mod (@mods) {
    my $diff = `git diff -b $mod 2>/dev/null`;
    if($diff) {
        print $mod."\n";
        if($auto_add eq "add") {
            `git add $mod 2>/dev/null`;
        }
    }
}

Código-fonte: https://github.com/lepe/scripts/blob/master/gitdiff.pl

Atualizações :

  • correção por evandro777: Quando o arquivo tem espaço no nome do arquivo ou diretório
lepe
fonte
Obrigado! Essa é a única maneira de conseguir a diferença real. Há apenas um problema que aconteceu com 3 linhas impressas, mostrando este erro: sh: 1: Erro de sintaxe: String entre aspas não
terminada
1
Uma correção para um problema de script: O problema: Quando o arquivo tem espaço em nome de arquivo ou diretório, o git usará "", então o script quebra. A correção é alterar esta linha: my @mods = git status --porcelain 2>/dev/null | grep '^ M ' | awk '{ print \$2 }'; para isso: meu @mods = git status --porcelain 2>/dev/null | grep '^ M ' | cut -c4-;
evandro777
@ evandro777: Obrigado! Eu atualizei a resposta e o código git.
lepe,
3

Eu uso windows e linux, mas a solução core.autocrlf truenão me ajudou. Eu ainda não mudei nada depois git checkout <filename>.

Então, eu uso uma solução alternativa para substituir git status-gitstatus.sh

#!/bin/bash

git status | grep modified | cut -d' ' -f 4 | while read x; do
 x1="$(git show HEAD:$x | md5sum | cut -d' ' -f 1 )"
 x2="$(cat $x | md5sum | cut -d' ' -f 1 )"

 if [ "$x1" != "$x2" ]; then
    echo "$x NOT IDENTICAL"
 fi
done

Acabei de comparar md5sumum arquivo e seu irmão no repositório.

Exemplo de saída:

$ ./gitstatus.sh
application/script.php NOT IDENTICAL
application/storage/logs/laravel.log NOT IDENTICAL
shukshin.ivan
fonte
2
talvez você possa usar "git diff -b" para cada arquivo para verificar as alterações alterações nos espaços em branco do excel
Ivan