Como posso visualizar diferenças por caractere em um arquivo diff unificado?

122

Digamos que eu crie um patch com git format-patch. O arquivo é basicamente um diff unificado com alguns metadados. Se eu abrir o arquivo no Vim, posso ver quais linhas foram modificadas, mas não consigo ver quais caracteres nas linhas alteradas diferem. Alguém conhece uma maneira (no Vim, ou algum outro software livre que roda no Ubuntu) para visualizar diferenças por caracteres?

Um exemplo de contador em que a diferença por caractere é visualizada é ao executar vimdiff a b .

atualização Fri Nov 12 22:36:23 UTC 2010

O diffpatch é útil para o cenário em que você está trabalhando com um único arquivo.

atualização quinta-feira 16 de junho 17:56:10 UTC de 2016

Confira diff-realce no git 2.9 . Esse script faz exatamente o que eu estava procurando originalmente.

Adam Monsen
fonte
Isso pode ser melhor no superuser.com
Daenyth
13
Possivelmente. Eu escolhi stackoverflow.com desde o FAQ menciona este é o lugar para perguntas sobre "ferramentas de software comumente usados por programadores"
Adam Monsen
7
Não tenho certeza de que isso responda diretamente à sua pergunta, mas git diff --color-wordsé muito útil apenas para ver quais palavras mudam dentro das linhas, em vez da saída diff unificada usual. Ele é baseado em palavras e não em caracteres, portanto, se não houver muito espaço em branco no conteúdo que você está difundindo, a saída poderá ser menos organizada. (Editado: Opa, eu vejo que eu mal o que você está pedindo - no entanto, talvez este comentário seria útil para alguém.)
Mark Longair

Respostas:

13

Dadas as suas referências ao Vim na pergunta, não tenho certeza se esta é a resposta que você deseja :), mas o Emacs pode fazer isso. Abra o arquivo que contém o diff, verifique se você está dentro diff-mode(se o arquivo for nomeado foo.diffou foo.patchisso acontecer automaticamente; caso contrário, digiteM-x diff-mode RET ), vá para o pedaço que você está interessado e bateu C-c C-bpara refine-hunk. Ou percorra o arquivo com um pedaço de cada vez M-n; isso fará o refinamento automaticamente.

legoscia
fonte
1
Funciona para mim! Hei, eu uso o Vim há 10 anos, mas acabei de instalar o emacs. :)
Adam Monsen
Mas o emacs não suporta a leitura de stdin, eu não posso fazer, por exemplogit log master.. -p | emacs -
Oi-Angel
1
@ Hi-Angel Você pode abrir o Emacs e digitar M-!para executar o comando e capturar a saída em um buffer.
Legoscia 19/10/19
172

No git, você pode mesclar sem confirmar. Mesclar seu patch primeiro e depois:

git diff --word-diff-regex=.

Observe o ponto após o sinal de igual.

yingted
fonte
139
Melhor: git diff --color-words=..
Ntc2 06/11/2013
4
@ ntc2 Você deve fazer do seu comentário uma resposta.
Tyler Collier
1
Upvoters observe, meu caso de uso original pressupõe que você tenha apenas um arquivo de correção , nenhum repositório Git ou mesmo versões base / modificadas. Por isso aceitei a resposta da @ legoscia ... descreve exatamente o que foi solicitado.
Adam Monsen 23/10
2
@ NT2 git diff --color-words=.e git diff --color-words .funciona de maneira diferente. Melhor é git diff --color-words ..
Abhisekp
2
@abhisekp: obrigado pela foto. Eu acho que descobri: o git diff --color-words .é realmente o mesmo que git diff --color-words -- .! Ou seja, o .é interpretado como um caminho. Você pode verificar com mkdir x y; echo foo > x/test; git add x/test; git commit -m test; echo boo > x/test; cd y; git diff --color-words=.; git diff --color-words .; git diff --color-words -- ..
Ntc2 4/09/15
145

Aqui estão algumas versões com menos saída ruidosa que git diff --word-diff-regex=<re>e que requerem menos digitação que, mas são equivalentes a git diff --color-words --word-diff-regex=<re>,.

Simples (destaca as alterações de espaço):

git diff --color-words

Simples (destaca alterações de caracteres individuais; não destaca alterações de espaço):

git diff --color-words=.

Mais complexo (destaca as alterações de espaço):

git diff --color-words='[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+'

Em geral:

git diff --color-words=<re>

onde <re>é um regexp que define "palavras" com o objetivo de identificar alterações.

Eles são menos barulhentos, pois colorem as "palavras" alteradas, enquanto o uso apenas --word-diff-regex=<re>envolve "palavras" correspondentes com -/+marcadores coloridos .

ntc2
fonte
9
Eu mesmo gosto --color-words, sem a =.parte.
Tyler Collier
1
git diff --color-words='\w'funcionaria melhor com diacríticos (git v1.7.10.4)
nr
1
Sua versão mais complexa funciona muito bem. Anexei --word-diff=plainadicionalmente a ter [-e -]deletar cercas {+e +}cercar adições. Como o manual adverte, no entanto, ocorrências reais desses delimitadores na fonte são não escapou de qualquer forma
Tobias KIENZLER
2
Infelizmente, sua versão mais complexa parece não destacar, por exemplo, alterações de recuo, eu abri uma pergunta sobre isso #
Tobias Kienzler
Esta resposta é ótima! No entanto, existe uma maneira de realmente alterar o plano de fundo dessas alterações para verde / vermelho?
WoLfPwNeR
45
git diff --color-words="[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+"

O regex acima ( de Thomas Rast ) faz um trabalho decente ao separar fragmentos diff no nível de pontuação / caractere (embora não seja tão barulhento quanto --word-diff-regex=.).

Publiquei uma captura de tela da saída resultante aqui .


Atualizar:

Este artigo tem algumas ótimas sugestões. Especificamente, a contrib/árvore do repositório git possui um diff-highlightscript perl que mostra destaques refinados.

Início rápido para usá-lo:

$ curl https://git.kernel.org/cgit/git/git.git/plain/contrib/diff-highlight/diff-highlight > diff-highlight
$ chmod u+x diff-highlight
$ git diff --color=always HEAD~10 | diff-highlight | less -R
Justin M. Keyes
fonte
5
Você pode abreviá-lo para--color-words=[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+'
Eddified
eu tive que adicionar 'ao início do valor lá. caso contrário, eu tenho um erro. Além disso, eu simplesmente usando --color-wordseu recebo exatamente o mesmo comportamento que usar esse regexp.
Gcb # 14/13
3
@gcb O conteúdo do texto é importante. Se suas alterações forem separadas por espaço em branco, não haverá diferença. Mas se você mudar se você mudar algo como foo.bara foo.quxque você vai ver a diferença.
Justin M. Keyes
5
Mais simples: git diff --color-words='[^[:space:]]|([[:alnum:]]|UTF_8_GUARD)+'.
Ntc2 06/11/2013
1
Eu tinha instalado o git com o Homebrew e já tinha esse script em /usr/local/share/git-core/contrib/diff-highlight/diff-highlight. Isso parece sugerir que o git de Homebrew instala todo o contrib /usr/local/share/git-core/contrib/. Então, finalmente, o seguinte trabalhou para mimgit diff --color=always | /usr/local/share/git-core/contrib/diff-highlight/diff-highlight
Ashutosh Jindal
6

Se você não tem nada contra instalar o NodeJS, existe um pacote chamado "diff-so-fancy" ( https://github.com/so-fancy/diff-so-fancy ), que é muito fácil de instalar e funciona perfeitamente:

npm install -g diff-so-fancy
git diff --color | diff-so-fancy | less -R

Edit: Acabei de descobrir que é realmente um invólucro para o diff-destaque oficial ... Pelo menos é mais fácil de instalar para perlofóbicos como eu e a página do GitHub está bem documentada :)

walnutz
fonte
2

Não conheço a ferramenta de diferença por caractere, mas existe uma ferramenta por diferença de palavra: wdiff.

consulte exemplos As 4 principais ferramentas de diferença de arquivos no UNIX / Linux - Diff, Colordiff, Wdiff, Vimdiff .

o geek
fonte
wdiff é interessante, obrigado! Para esclarecer minha pergunta original, estou procurando por algo que forneça realce de sintaxe aprimorado para um único arquivo que esteja no formato diff unificado.
Adam Monsen
Ligeiramente offtopic (sobre diferenças de palavra por palavra, não aprimorando uma saída de diferenças preexistente), mas eu achei as seguintes combinações melhores para visualizações de palavra por palavra: * wdiff old_file new_file | cdiff * vimdiff , depois dentro do vim :windo wincmd Kpara mudar para o layout vertical da janela (um abaixo do outro) lado a lado. Esse layout é muito melhor para arquivos com linhas longas.
Aleksander Adamowski
2
BTW, algumas outras ferramentas vale a pena conferir, não mencionados no artigo ligado: wdiff2, mdiffe a ferramenta on-line do Google .
Aleksander Adamowski
1

Depois de um pouco de pesquisa, percebo que essa pergunta surgiu duas vezes recentemente na lista de discussão principal do Vim. O plugin NrrwRgn foi mencionado nas duas vezes (crie duas regiões estreitas e as diferencie). Usar o NrrwRgn, como descrito por Christian Brabandt, parece mais uma solução alternativa do que uma solução, mas talvez isso seja bom o suficiente.

Experimentei o NrrwRgn e, junto com: diffthis, foi realmente útil para ilustrar diferenças por caractere em partes de um único arquivo. Mas foram necessárias muitas teclas. Meu Vimscript está bastante enferrujado, mas provavelmente pode ser roteirizado. Talvez o NrrwRgn possa ser aprimorado para fornecer a funcionalidade desejada.

Pensamentos?

Adam Monsen
fonte