É possível que o git-merge ignore as diferenças de final de linha?

150

É possível git mergeignorar as diferenças de final de linha?

Talvez eu esteja fazendo a pergunta errada ... mas:

Eu tentei usar, config.crlf inputmas as coisas ficaram um pouco confusas e fora de controle, especialmente quando eu a apliquei após o fato .

Por um lado, a aplicação dessa configuração após o fato não parece afetar os arquivos que foram confirmados no repositório antes de aplicar esta opção. Outra coisa é que, de repente, todas as confirmações agora resultam em muitas mensagens de aviso irritantes sobre o CRLF sendo convertidas em LF.

Para ser sincero, eu realmente não me importo com o final de linha usado, eu pessoalmente prefiro o estilo Unix \n, mas tanto faz. Tudo o que me interessa é git mergeser um pouco mais inteligente e ignorar as diferenças nos finais de linha.

Às vezes, tenho dois arquivos idênticos, mas o git os marca como estando em conflito (e o conflito é o arquivo inteiro ) simplesmente porque eles usam um caractere final de linha diferente.

Atualizar:

Descobri que git diffaceita uma --ignore-space-at-eolopção, seria possível deixar de git mergeusar essa opção também?

hasen
fonte
28
Oh eu desejo. Essa coisa de final de linha no git está totalmente quebrada
1800 INFORMAÇÃO
Acabou de adicionar um caso de teste que ilustram os ferramenta de mesclagem de terceiros irá ignorar estilo EOL durante uma mala
VonC
Então, para esclarecer (pelo que posso determinar): não há como o git ignorar os CRs, mas reclamar de todos os outros espaços em branco à direita?
Stephen
Certifique-se de dar uma olhada na resposta abaixo sobregit config merge.renormalize true
qneill

Respostas:

115

Atualização 2013:

Versões git mais recentes autorizam o uso da mesclagem com a estratégia recursivee a opção de estratégia ( -X):

git merge -s recursive -Xignore-space-at-eol

Mas usar " -Xignore-space-change" também é uma possibilidade

  • Fab-V menciona abaixo :
    mestre de mesclagem do git -s recursivo -X renormaliza
    
    

O jakub.g também comenta que as estratégias também funcionam com a colheita de cerejas :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Isso funciona muito melhor que ignore-all-space.


Resposta original (maio de 2009)

O patch para ignorar o estilo eol foi proposto em junho de 2007 , mas apenas diz respeito git diff --ignore-space-at-eol, não git merge.

Na época, a pergunta foi feita:

Deve --ignore-space-at-eolser uma opção para git-merge?
Mesclagens são onde essa funcionalidade é importante.
Quais são as semânticas de uma mesclagem auto-resolvida com essas opções em vigor - elas são usadas apenas para a detecção de renomeação ou, por exemplo, não sinalizamos conflitos apenas com alterações de espaço em branco? E se não, qual versão aceitamos automaticamente?

Julio C Hamano não estava exatamente entusiasmado:

Isso certamente é tentador, mas suspeito que isso deva ser deixado para as rodadas posteriores.
Suspeito que ele introduzisse um conceito de dois tipos diferentes de diferenças, uma a ser processada mecanicamente (ou seja, uso em mesclagem com "git-merge-recursive" e se aplica a "git-am") e outra a ser inspecionada por humanos para entender.
Muitas vezes, pode ser útil mover a entrada para o último caso, mesmo que a saída da comparação de arquivos de entrada intermediários possa não ser facilmente utilizável para aplicação mecânica.

A idéia geral, quando se trata git merge, é confiar na ferramenta de mesclagem de terceiros.

Por exemplo, eu configurei o DiffMerge para ser a ferramenta para mesclagem do Git, definindo um conjunto de regras que permite que a ferramenta de mesclagem ignore o eol em determinados tipos de arquivos.


Instalação no Windows, com o MSysGit1.6.3, para a sessão do DOS ou Git bash, com o DiffMerge ou o KDiff3:

  • defina um diretório em seu PATH (aqui:) c:\HOMEWARE\cmd.
  • adicione nesse diretório o script merge.sh (wrapper para sua ferramenta de mesclagem favorita)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Declarar seu wrapper de mesclagem para Git

Comandos de configuração do Git:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Verifique se autoCRLF é falso

configuração do git no nível do sistema:

git config ---system core.autoCRLF=false
  • Teste se, quando duas linhas são idênticas (mas seus caracteres EOL), o DiffMerge ou o KDiff3 ignoram essas linhas durante uma mesclagem.

Script DOS (nota: o comando dos2unix vem daqui e é usado para simular um estilo Unol eol. Esse comando foi copiado no diretório mencionado no início desta resposta.):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

Nesse ponto (pressionando "return"), o DiffMerge ou o KDiff3 serão abertos e você verá por si mesmo quais linhas são realmente mescladas e quais são ignoradas.

Aviso : o arquivo de resultado estará sempre no modo Windows eol (CRLF) com o DiffMerge ... O
KDiff3 oferece para salvar de uma maneira ou de outra.

VonC
fonte
Obrigado pela dica! Meld e FileMerge no Mac também parecem ótimos aplicativos.
Léo Léopold Hertz,
1
Para sua informação, as estratégias de trabalhar também com cherry-picking : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (isso funciona muito melhor do que ignore-all-space)
jakub.g
1
@ jakub.g bom ponto! Eu o incluí na resposta para obter mais visibilidade.
VonC 10/10
98

Eu estava procurando a mesma resposta e descobri isso

Mesclando ramificações com diferentes atributos de check-in / check-out

Se você adicionou atributos a um arquivo que faz com que o formato do repositório canônico seja alterado, como a adição de um filtro clean / smudge ou atributos text / eol / ident, mesclar qualquer coisa em que o atributo não esteja no lugar normalmente causaria conflitos de mesclagem .

Para evitar esses conflitos desnecessários de mesclagem, pode-se dizer ao git para executar um check-out e check-in virtuais dos três estágios de um arquivo ao resolver uma mesclagem de três vias, definindo a variável de configuração merge.renormalize. Isso evita que as alterações causadas pela conversão de check-in causem conflitos de mesclagem falsos quando um arquivo convertido é mesclado com um arquivo não convertido.

Desde que um "smudge → clean" resulte na mesma saída que um "clean", mesmo em arquivos que já foram smudged, essa estratégia resolverá automaticamente todos os conflitos relacionados ao filtro. Os filtros que não agem dessa maneira podem causar conflitos adicionais de mesclagem que devem ser resolvidos manualmente.

Portanto, executar este comando em qualquer repositório fará o truque:

git config merge.renormalize true
Fabio
fonte
20
Isso merece agora ser a resposta padrão. Muita coisa mudou desde que a pergunta foi feita pela primeira vez, o manuseio disso pelo git agora é incorporado com mesclagem. Normalize como você diz.
Anton I. Sipos
Este é apenas incrível .. salva meu dia
matthaeus
4

O que fiz foi deixar tudo como padrão (por exemplo, autocrlf = true), tocar em todos os arquivos (encontrar. -Exec touch {} \;), deixar o git vê-los como 'modificados' e enviá-los de volta, e pronto. Caso contrário, você sempre será atormentado por mensagens irritantes ou diferenças surpreendentes, ou terá que desativar todos os recursos de espaço em branco do git.

Você perderá informações de culpa, mas é melhor fazê-lo mais cedo ou mais tarde :)

Ben Hymers
fonte
4

"git merge -Xrenormalize" funciona como um encanto.

Jake
fonte
1

http://stahlforce.com/dev/index.php?tool=remcrlf

Eu tentei, mas se após a última linha do seu código você ainda não tinha o CRLF, ele adiciona por si só um LF e o arquivo parece alterado no git. Fora isso, funciona.

homem Formiga
fonte
0

Parece-me agora que a melhor maneira é normalizar as terminações de linha nos dois ramos (e confirmar) antes de mesclá-los.

Pesquisei "converter crlf em lf" no Google e achei isso como o primeiro resultado:
http://stahlforce.com/dev/index.php?tool=remcrlf

Eu baixei e usei, parece uma boa ferramenta.

>sfk remcr . .py

Certifique-se de especificar um diretório e um tipo de arquivo (por exemplo, .py), caso contrário, ele poderá tentar mexer com o conteúdo do .gitdiretório!

hasen
fonte
0

AFAICT, (ainda não tentei), você pode git diffcomparar o ramo que deseja mesclar ao ancestral comum e aplicar os resultados git apply. Ambos os comandos têm --ignore-whitespaceopções para ignorar erros de final de linha e espaço em branco.

Infelizmente, se o patch não se aplicar corretamente, toda a operação será abortada. Você não pode corrigir conflitos de mesclagem. Há uma --rejectopção para deixar pedaços incontroláveis ​​nos .rejarquivos, o que ajuda, mas não é o mesmo que ter os conflitos de mesclagem mostrados em um arquivo.

rjmunro
fonte
-1

Depois de ler Resolver conflitos de mesclagem: Forçar a substituição de todos os arquivos

Finalmente resolvi minha versão deste problema. Eu estava tentando obter atualizações do repositório upstream, mas o atual estava tendo problemas relacionados ao CRLF e não foi possível mesclar como resultado. Note-se que eu não tinha mudanças locais que eu precisava me preocupar. Os seguintes passos resolveram o meu problema:

Conforme as instruções do github sobre sincronização de garfos ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Meu entendimento limitado do git me diz que isso está fazendo o que eu quero - reformulando meu fork (sem alterações reais não confirmadas) para obter todas as alterações feitas na fonte upstream. De acordo com a página de origem, essa etapa normalmente não deve ser necessária, mas o problema da CRLF exigiu.

  3. git merge upstream/master

  4. git push
propagado
fonte
1
Você percebe que git reset --hard upstream/masterjoga fora sua filial local e aponta para ela upstream/master, fazendo git merge upstream/masterum não-op?
Christoffer Hammarström
-1

no entanto, sugiro usar ferramentas como sed para obter finais de linha corretos e, em seguida, arquivos diff. Passei algumas horas no diffing projetos com vários finais de linha.

A melhor maneira era:

  1. copie apenas os arquivos do projeto (omitir .gitdiretório) para outro diretório, crie um repositório nele e adicione-os e confirme-os (deve estar na ramificação principal do novo repositório).
  2. copie arquivos do segundo projeto para a mesma pasta, mas outro ramo, por exemplo dev( git checkout -b dev), confirme arquivos nesse ramo e execute (se o primeiro projeto estiver no mestre): git diff master..dev --names-only para ver apenas os nomes dos arquivos alterados
user4686964
fonte