Como diferencio o mesmo arquivo entre duas confirmações diferentes no mesmo ramo?

1144

No Git, como eu poderia comparar o mesmo arquivo entre dois commits diferentes (não contíguos) no mesmo ramo (master por exemplo)?

Estou procurando um recurso de comparação como o Visual SourceSafe (VSS) ou o Team Foundation Server (TFS).
É possível no Git?

systempuntoout
fonte

Respostas:

1476

Na página de git-diffmanual:

git diff [--options] <commit> <commit> [--] [<path>...]

Por exemplo, para ver a diferença de um arquivo "main.c" entre agora e duas confirmações, aqui estão três comandos equivalentes:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
mipadi
fonte
43
O ..não é realmente necessário, embora funcione com ele (exceto em versões bastante antigas, talvez). Você também pode usar git logou gitkencontrar SHA1s para usar, caso os dois commits estejam muito distantes. gitktambém possui um "diff selected -> this" e "diff this -> selected" em seu menu de contexto.
Cascabel 26/07
17
Isso funcionará mesmo que o nome do arquivo tenha sido modificado entre as duas confirmações?
Reebenjohn
26
Então, qual é o objetivo do "-"
user64141
29
@ user64141 Isso --é útil, por exemplo, quando você tem um arquivo chamado -p. É bom usar em scripts, apenas em casos raros necessários na prática.
Palec
13
Nota: você precisa usar caminhos relativos à raiz do repositório. Os caminhos relativos ao diretório de trabalho atual não funcionarão.
Kevin Wheeler
281

Você também pode comparar dois arquivos diferentes em duas revisões diferentes, assim:

git diff <revision_1>:<file_1> <revision_2>:<file_2>

Jakub Narębski
fonte
25
nota que parece que se <file_1>e <file_2>estão no diretório atual, não no diretório de nível superior git gerenciado, um tem que preceder ./em Unix:<revision_1>:./filename_1
Andre Holzner
7
<revisão>: pode ser omitido, para que você possa diferenciar um arquivo que ainda não foi confirmado.
Yaroslav Nikitenko
2
Observe que no Windows é necessário usar '/' para caminhos de arquivo, não '\'.
Np8 23/10/18
88

Se você configurou o "difftool", pode usar

git difftool revision_1:file_1 revision_2:file_2

Exemplo: Comparando um Arquivo da Última Confirmação com a Confirmação Anterior na Mesma Ramificação: Supondo que, se você estiver na pasta raiz do projeto

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

Você deve ter as seguintes entradas no seu arquivo ~ / .gitconfig ou no projeto / .git / config. Instale o p4merge [Esta é minha ferramenta preferida de difusão e mesclagem]

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
Anver Sadhat
fonte
50

Verifique $ git log, copie o ID SHA-1 das duas confirmações diferentes e execute o git diffcomando com esses IDs. por exemplo:

$ git diff (sha-id-one) (sha-id-two)
Vibhuti
fonte
18
Se você deseja o diff para um arquivo específico, adicione o caminho no final do comando.
Hbrent
Também faça um "git pull" para baixar as informações completas da árvore se os dois commits estiverem em diferentes ramificações. Caso contrário, você receberá um erro "fatal: bad object".
User238607
4
git diff (sha-id-one) (sha-id-two) -- filename.ext sem o nome do arquivo, ele listará as diferenças de todos os arquivos nesses dois commits.
precisa saber é o seguinte
40

Se você quiser ver todas as alterações no arquivo entre as duas confirmações em uma base de confirmação por confirmação, também poderá fazer

git log -u $start_commit..$end_commit -- path/to/file

cxreg
fonte
O que são "$ start_commit" e "$ end_commit"? Eles são literais ou, se não, você pode fornecer um exemplo?
Peter Mortensen
Essas são variáveis do shell que contêm a revisão de início e fim, o que pode em vez disso ser literais SHA1 ou refs
cxreg
21

Aqui está um script Perl que imprime os comandos diff do Git para um determinado arquivo, conforme encontrado em um comando de log do Git.

Por exemplo

git log pom.xml | perl gldiff.pl 3 pom.xml

Rendimentos:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

que poderia ser recortado e colado em uma sessão de janela de shell ou canalizado para /bin/sh.

Notas:

  1. o número (3 neste caso) especifica quantas linhas imprimir
  2. o arquivo (pom.xml neste caso) deve concordar nos dois lugares (você pode envolvê-lo em uma função shell para fornecer o mesmo arquivo nos dois lugares) ou colocá-lo em um diretório binário como um script shell

Código:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}
user2520657
fonte
14

Se você quiser fazer uma comparação com mais de um arquivo, com o método especificado por @mipadi:

Por exemplo, diff between HEADe your master, para encontrar todos os .coffeearquivos:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

Isso pesquisará recursivamente your_search_folder/todos os .coffeearquivos e fará uma diferença entre eles e suas masterversões.

Andrei-Niculae Petre
fonte
13

Se você possui vários arquivos ou diretórios e deseja comparar confirmações não contínuas, faça o seguinte:

Faça uma ramificação temporária ( "revisão" neste exemplo)

git checkout -b revision

Retroceder para o primeiro destino de confirmação

git reset --hard <commit_target>

Cereja escolhendo aqueles que se interessam

git cherry-pick <commit_interested> ...

Apply diff

git diff <commit-target>^

Quando você terminou

git branch -D revision
dvdvck
fonte
2
Obrigado por esta solução. Funcionou bem para o meu caso de uso. A única coisa que eu atualizaria é que, quando terminar, você não poderá excluir o ramo até que o desative.
Steven Dix
9

Apenas outra maneira de usar a grandiosidade do Git ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
Eddie B
fonte
I definido um alias a partir desta resposta que funciona com bash:difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
blueogive
2

Se você deseja uma comparação visual simples no Windows, como é possível obter no Visual SourceSafe ou no Team Foundation Server (TFS), tente o seguinte:

  • clique com o botão direito do mouse no arquivo no File Explorer
  • selecione 'Histórico do Git'

Nota: Após a atualização para o Windows 10, perdi as opções do menu de contexto do Git. No entanto, você pode conseguir o mesmo usando 'gitk' ou 'gitk filename' em uma janela de comando.

Depois de chamar 'Git History', a ferramenta Git GUI será iniciada, com um histórico do arquivo no painel superior esquerdo. Selecione uma das versões que você gostaria de comparar. Em seguida, clique com o botão direito do mouse na segunda versão e escolha

Dif - -> selecionado

ou

Dif. Selecionado -> este

As diferenças codificadas por cores aparecerão no painel inferior esquerdo.

Recurso
fonte
Nota para os que recusam: esta é uma solução simples, fácil de implementar e soluciona o problema do OP. Ele funciona no Windows que o OP está usando claramente (consulte as referências ao TFS e ao VSS na pergunta).
Resource