Como posso obter uma comparação lado a lado quando faço o "git diff"?

163

Quando digito "git diff", gostaria de ver um diff lado a lado, como com "diff -y", ou gostaria de exibir o diff em uma ferramenta de diff interativa como "kdiff3". Como isso pode ser feito?

Mike
fonte

Respostas:

89

Embora o Git tenha uma implementação interna do diff, você pode configurar uma ferramenta externa.

Existem duas maneiras diferentes de especificar uma ferramenta de comparação externa:

  1. definindo as GIT_EXTERNAL_DIFFeo GIT_DIFF_OPTSambiente variáveis.
  2. configurando a ferramenta diff externa via git config

Veja também:

Ao fazer a git diff, o Git verifica as configurações das variáveis ​​de ambiente acima e seu .gitconfigarquivo.

Por padrão, o Git passa os sete argumentos a seguir para o programa diff:

path  old-file  old-hex old-mode  new-file  new-hex new-mode

Normalmente, você só precisa dos parâmetros do arquivo antigo e do novo arquivo. É claro que a maioria das ferramentas diff usa apenas dois nomes de arquivos como argumento. Isso significa que você precisa escrever um pequeno script wrapper, que aceita os argumentos que o Git fornece ao script e os entrega ao programa externo do git de sua escolha.

Digamos que você coloque seu wrapper-script em ~/scripts/my_diff.sh:

#!/bin/bash
# un-comment one diff tool you'd like to use

# side-by-side diff with custom options:
# /usr/bin/sdiff -w200 -l "$2" "$5" 

# using kdiff3 as the side-by-side diff:
# /usr/bin/kdiff3 "$2" "$5"

# using Meld 
/usr/bin/meld "$2" "$5"

# using VIM
# /usr/bin/vim -d "$2" "$5"

você precisa tornar esse script executável:

chmod a+x ~/scripts/my_diff.sh

você precisará informar ao Git como e onde encontrar seu script de wrapper diff personalizado. Você tem três opções de como fazer isso: (prefiro editar o arquivo .gitconfig)

  1. Usando GIT_EXTERNAL_DIFF,GIT_DIFF_OPTS

    Por exemplo, no seu arquivo .bashrc ou .bash_profile, você pode definir:

    GIT_EXTERNAL_DIFF=$HOME/scripts/my_diff.sh
    export GIT_EXTERNAL_DIFF
    
  2. Usando git config

    use "git config" para definir onde seu script wrapper pode ser encontrado:

    git config --global diff.external ~/scripts/my_diff.sh
    
  3. Editando seu ~/.gitconfigarquivo

    você pode editar seu ~/.gitconfigarquivo para adicionar estas linhas:

    [diff]
      external = ~/scripts/my_diff.sh
    

Nota:

De maneira semelhante à instalação da ferramenta diff personalizada, você também pode instalar uma ferramenta de mesclagem personalizada, que pode ser uma ferramenta de mesclagem visual para ajudar a visualizar melhor a mesclagem. (veja a página progit.org)

Consulte: http://fredpalma.com/518/visual-diff-and-merge-tool/ e https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration

Tilo
fonte
1
Isso mantém a coloração do terminal git?
Sridhar Sarnobat 31/07
3
Isso é ótimo, mas lança um novo visualizador para cada arquivo. Qualquer maneira de criar uma diferença consolidada, digamos meld,?
HRJ 12/11
2
@Tilo estou recebendo erro para o vim como im: Aviso: A saída não é um terminal
programador mortos
A meldversão pode ser configurada para fazer uma comparação de diretório, onde posso escolher para quais arquivos quero ver a comparação? Atualmente, ele executa um meldcomando separado para cada arquivo, e eu tenho que sair meldpara ver o próximo arquivo. Prefiro meldme mostrar uma lista de diretórios de arquivos alterados, como se comporta quando meldé usado no Mercurial.
kasperd
163

Experimente o git difftool

Use em git difftoolvez de git diff. Você nunca voltará.

UPDATE para adicionar um exemplo de uso:

Aqui está um link para outro stackoverflow que fala sobre git difftool: Como visualizo a saída 'git diff' com minha ferramenta / visualizador preferido de diff?

Para versões mais recentes do git, o difftoolcomando suporta muitas ferramentas externas diff prontas para uso. Por exemplo, vimdiffé suportado automaticamente e pode ser aberto na linha de comando:

cd /path/to/git/repo
git difftool --tool=vimdiff

Outras ferramentas de diff externas suportadas são listadas git difftool --tool-helpaqui, é um exemplo de saída:

'git difftool --tool=<tool>' may be set to one of the following:
        araxis
        kompare
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        bc3
        codecompare
        deltawalker
        diffuse
        ecmerge
        emerge
        gvimdiff
        gvimdiff2
        kdiff3
        meld
        opendiff
        tkdiff
        xxdiff
Matt Ball
fonte
34
Ou talvez você volte se conseguir This message is displayed because 'diff.tool' is not configured.. Talvez atualize a resposta com o mínimo de como configurar essa coisa, para que ela exiba diferenças lado a lado no terminal, o que o OP pediu? As ferramentas da GUI são bastante inúteis no servidor remoto onde você se conecta usando o ssh.
Petr
1
Ponto interessante, embora eu ache que nunca precisei usar o git enquanto estiver no SSH. Uma das coisas boas do DVCS é a parte Distribuída: pelo menos em meus ambientes, nunca é difícil clonar localmente qualquer repo que eu queira bisbilhotar.
Matt Ball
1
Pelo menos na minha configuração, git difftoolcom vimdiffnem sempre se alinham os dois arquivos / buffers corretamente.
precisa
1
Isso é bom, e assim abaixo na lista de respostas: uso OI git difftool -ypara evitar tkdiff pronta
harshvchawla
Relacionado: faça o seu meld git difftoolno Windows e Linux: stackoverflow.com/a/48979939/4561887
Gabriel Staples
55

Você também pode tentar git diff --word-diff. Não é exatamente lado a lado, mas de alguma forma melhor, então você pode preferir à sua real necessidade lado a lado.

mb14
fonte
12
Esta é a maneira mais fácil. O que é ainda melhor égit diff --word-diff=color
Rolf
@Rolf --word-diff=colorme dá um erro de opção inválida. Em qual versão foi introduzida?
Holloway
@Trengot eu corro git 1.7.9 que é de 02/2012
Rolf
4
A versão instalada padrão do @Rolf aqui é 1.7.1. Poderia explicar a diferença. git diff --color-wordsfunciona.
Holloway
4
Sim, git diff --color-wordsé o caminho a seguir nas versões modernas do git.
precisa saber é o seguinte
41

ydiff

Anteriormente chamada cdiff, essa ferramenta pode exibir diferenças lado a lado , incremental e colorida .

Em vez de fazer git diff, faça:

ydiff -s -w0

Isso será iniciado ydiffno modo de exibição lado a lado para cada um dos arquivos com diferenças.

Instale com:

python3 -m pip install --user ydiff

-ou-

brew install ydiff

Para git log, você pode usar:

ydiff -ls -w0

-w0detecta automaticamente a largura do seu terminal. Veja a ydiff página do repositório do GitHub para detalhes e demonstração.

Testado no Git 2.18.0, ydiff 1.1.

ymattw
fonte
@RyneEverett: Você pode explicar como fazer o equivalente git diff | cdiff -sao icdiff?
einpoklum
Basta executar a ydiff -spartir de um espaço de trabalho git / svn / hg, você não precisa
entrar
se você quiser limitar o diff a um arquivo específico através da história do Git cd <git repo>e , em seguida, executeydiff -ls <path/to/file>
slm
22

Você pode fazer um lado a lado diffusando sdiffo seguinte:

$ git difftool -y -x sdiff  HEAD^ | less

Onde HEAD^está um exemplo que você deve substituir pelo que você quer diferenciar.

Encontrei esta solução aqui, onde há algumas outras sugestões também. No entanto, essa resposta é a pergunta do OP de maneira sucinta e clara.

Veja o man git-difftool para uma explicação dos argumentos.


Levando os comentários em consideração, você pode criar um git sdiffcomando útil escrevendo o seguinte script executável:

#!/bin/sh
git difftool -y -x "sdiff -w $(tput cols)" "${@}" | less

Salve como /usr/bin/git-sdiffe chmod -x. Então você poderá fazer isso:

$ git sdiff HEAD^
starfry
fonte
Eu costumo fazer "$ git difftool -x 'sdiff -s -w 240'" (ou qualquer largura de tela) se / quando quiser suprimir as mesmas linhas e houver apenas um arquivo (caso contrário, faço o vimdiff)
HidekiAI
1
@HidekiAI Acho que é uma dor de digitar o terminal de largura cada vez, então eu uso tput colsem vez disso, por exemplo: git difftool -x "sdiff -s -w $(tput cols)".
jaume
ele pode destacar as mudanças de cor? No momento, parece que precisamos usar nossos olhos para identificar quais são as mudanças
polaridade
Substitua sdiff por icdiff para obter uma bela exibição em cores.
Greg
10
export GIT_EXTERNAL_DIFF='meld $2 $5; echo >/dev/null'

então simplesmente:

git diff
Krzych
fonte
1
`meld. ' funciona também! E mostra todas as alterações em uma janela consolidada.
HRJ 12/11
@HRJ que funciona perfeitamente! Tão simples e prático :)
waldyrious
9

Se você quiser ver diferenças lado a lado em um navegador sem envolver o GitHub, poderá desfrutar do git webdiff , um substituto para git diff:

$ pip install webdiff
$ git webdiff

Isso oferece várias vantagens sobre os difftools da GUI tradicional, como tkdiffno sentido de oferecer realce de sintaxe e mostrar diferenças de imagem.

Leia mais sobre isso aqui .

danvk
fonte
7

Eu uso colordiff .

No Mac OS X, instale-o com

$ sudo port install colordiff

No Linux, é possível apt get install colordiffou algo assim, dependendo da sua distribuição.

Então:

$ git difftool --extcmd="colordiff -ydw" HEAD^ HEAD

Ou crie um alias

$ git alias diffy "difftool --extcmd=\"colordiff -ydw\""

Então você pode usá-lo

$ git diffy HEAD^ HEAD

Eu o chamei de "diffy" porque diff -yé o diff lado a lado no unix. Colordiff também adiciona cores mais agradáveis. Na opção -ydw, yé para o lado a lado, wé para ignorar espaços em branco e dé para produzir a diferença mínima (geralmente você obtém um melhor resultado como diferença)

Luigi R. Viggiano
fonte
adicione -ypara ignorar o Launch 'colordiff' [Y/n]:prompt.
Beni Cherniavsky-Paskin
você tem certeza que é git alias diffy "difftool --extcmd=\"colordiff -ydw\""? Não deveria ser git config --global alias.diffy "difftool --extcmd=\"colordiff -ydw\""?
nonopolarity
6

Para unix, combinando just gite o built-in diff:

git show HEAD:path/to/file | diff -y - path/to/file

Obviamente, você pode substituir HEAD por qualquer outra referência git e provavelmente deseja adicionar algo como -W 170o comando diff.

Isso pressupõe que você está apenas comparando o conteúdo do diretório com uma confirmação anterior. Comparar entre dois commits é mais complexo. Se o seu shell for, bashvocê pode usar "substituição de processo":

diff -y -W 170 <(git show REF1:path/to/file) <(git show REF2:path/to/file)

onde REF1e REF2são referências git - tags, ramificações ou hashes.

Walker Hale IV
fonte
Obrigado - seu comando 'git show HEAD: caminho / para / arquivo' era o que eu precisava para criar minha própria solução, 'vimdfiff <(git show HEAD: caminho / para / arquivo) caminho / para / arquivo'. Os bits ainda não estão alinhados corretamente, mas essa é a melhor solução que tenho no momento.
talexb
5

Eu pessoalmente gosto muito de icdiff !

Se você estiver em Mac OS Xcom HomeBrew, apenas faça brew install icdiff.

Para obter os rótulos dos arquivos corretamente, além de outros recursos interessantes, tenho no meu ~/.gitconfig:

[pager]
    difftool = true
[diff]
    tool = icdiff
[difftool "icdiff"]
    cmd = icdiff --head=5000 --highlight --line-numbers -L \"$BASE\" -L \"$REMOTE\" \"$LOCAL\" \"$REMOTE\"

E eu uso como: git difftool

Jose Alban
fonte
3

Essa pergunta apareceu quando eu estava procurando uma maneira rápida de usar o git builtin para localizar diferenças. Meus critérios de solução:

  • Inicialização rápida, opções internas necessárias
  • Pode lidar com muitos formatos facilmente, xml, diferentes linguagens de programação
  • Identifique rapidamente pequenas alterações de código em grandes arquivos de texto

Encontrei esta resposta para obter cores no git.

Para obter diferenças lado a lado em vez de diferenças de linha, ajustei a excelente resposta do mb14 nesta pergunta com os seguintes parâmetros:

$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]"

Se você não gostar do extra [- ou {+, a opção --word-diff=colorpode ser usada.

$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]" --word-diff=color

Isso ajudou a obter uma comparação adequada com o texto json e xml e o código java.

Em resumo, as --word-diff-regexopções têm uma visibilidade útil, juntamente com as configurações de cores, para obter uma experiência colorida do código-fonte lado a lado em comparação com o diferencial de linha padrão, ao navegar por arquivos grandes com pequenas alterações de linha.

Mike
fonte
3

Vários outros já mencionaram o cdiff para diferenciar lado a lado do git, mas ninguém deu uma implementação completa dele.

Setup cdiff:

git clone https://github.com/ymattw/cdiff.git
cd cdiff
ln -s `pwd`/cdiff ~/bin/cdiff
hash -r # refresh your PATH executable in bash (or 'rehash' if you use tcsh)
        # or just create a new terminal

Edite ~ / .gitconfig inserindo estas linhas:

[pager]
        diff = false
        show = false

[diff]
        tool = cdiff
        external = "cdiff -s $2 $5 #"

[difftool "cdiff"]
        cmd = cdiff -s \"$LOCAL\" \"$REMOTE\"

[alias]
        showw = show --ext-dif

O pager desativado é necessário para que o cdiff funcione com o Diff, ele é essencialmente um pager de qualquer maneira, portanto está ótimo. A ferramenta Difftool funcionará independentemente dessas configurações.

O alias show é necessário porque o git show suporta apenas ferramentas diff externas via argumento.

O '#' no final do comando externo diff é importante. O comando diff do Git anexa um $ @ (todas as variáveis ​​diff disponíveis) ao comando diff, mas queremos apenas os dois nomes de arquivos. Então, chamamos esses dois explicitamente com US $ 2 e US $ 5 e, em seguida, ocultamos o $ @ por trás de um comentário que, de outra forma, confundiria sdiff. Resultando em um erro parecido com:

fatal: <FILENAME>: no such path in the working tree
Use 'git <command> -- <path>...' to specify paths that do not exist locally.

Comandos Git que agora produzem diferenças lado a lado:

git diff <SHA1> <SHA2> 
git difftool <SHA1> <SHA2>
git showw <SHA>

Uso de Cdiff:

'SPACEBAR' - Advances the page of the current file.
'Q'        - Quits current file, thus advancing you to the next file.

Agora você tem diff lado a lado via git diff e difftool. E você tem o código-fonte cdiff python para personalização de usuários avançados, caso precise.

Eric
fonte
2

Aqui está uma abordagem. Se você passar por menos, a largura xterm é definida como 80, o que não é tão quente. Mas se você prosseguir com o comando, por exemplo, COLS = 210, poderá utilizar o xterm expandido.

gitdiff()
{
    local width=${COLS:-$(tput cols)}
    GIT_EXTERNAL_DIFF="diff -yW$width \$2 \$5; echo >/dev/null" git diff "$@"
}
Thomas Mellman
fonte
1
Engraçado. Eu assinei pelo nome com um pseudônimo, mas isso foi ignorado ... Obrigado por me divulgar, Stack Overflow. :(
Thomas Mellman
2

Abra Intellij IDEA , selecione uma confirmação única ou múltipla na janela da ferramenta "Controle de Versão", procure os arquivos alterados e clique duas vezes neles para inspecionar as alterações lado a lado de cada arquivo.

Com o iniciador de linha de comando incluído, você pode trazer o IDEA para qualquer lugar com um simples idea some/path

visão de controle de versão visão diferencial

Holger Brandl
fonte
1

Há muitas boas respostas neste tópico. Minha solução para esse problema foi escrever um script.

Nomeie esse 'git-scriptname' (e torne-o executável e coloque-o no PATH, como qualquer script), e você pode invocá-lo como um comando normal do git executando

$ git scriptname

A funcionalidade real é apenas a última linha. Aqui está a fonte:

#!/usr/bin/env zsh
#
#   Show a side-by-side diff of a particular file how it currently exists between:
#       * the file system
#       * in HEAD (latest committed changes)

function usage() {
    cat <<-HERE
    USAGE

    $(basename $1) <file>

    Show a side-by-side diff of a particular file between the current versions:

        * on the file system (latest edited changes)
        * in HEAD (latest committed changes)

HERE
}

if [[ $# = 0 ]]; then
    usage $0
    exit
fi

file=$1
diff -y =(git show HEAD:$file) $file | pygmentize -g | less -R
Jon Carter
fonte
1

Esta pode ser uma solução um tanto limitada, mas executa o trabalho usando o diffcomando do sistema sem ferramentas externas:

diff -y  <(git show from-rev:the/file/path) <(git show to-rev:the/file/path)
  • filtre apenas as linhas de mudança usadas --suppress-common-lines(se o seu diffsuportar a opção).
  • sem cores neste caso, apenas os diffmarcadores usuais
  • pode ajustar a largura da coluna --width=term-width; no Bash pode obter a largura como $COLUMNSou tput cols.

Isso também pode ser envolvido em um script git helper para maior comodidade, por exemplo, uso como este:

git diffy the/file/path --from rev1 --to rev2
nomadbyte
fonte