Como fazer um diff git no arquivo movido / renomeado?

128

Mudei um arquivo usando git mv. Agora eu gostaria de fazer uma diferença no novo arquivo para compará-lo com o arquivo antigo (com o nome antigo, agora inexistente).

Como eu faço isso?

dr jerry
fonte
4
Em breve (git 2.9, junho de 2016), um simples git diff -- yourRenamedFileserá suficiente. Veja minha resposta abaixo
VonC:

Respostas:

145

Você precisa usar -M para permitir que o git detecte automaticamente o arquivo movido durante a difusão. Usar apenas git diffcomo mencionado não funciona para mim.

Tão simplesmente: git diff -Mdeve fazê-lo.

A documentação para esta opção é:

-M[<n>], --find-renames[=<n>]
       Detect renames. If n is specified, it is a threshold on the similarity index 
       (i.e. amount of addition/deletions compared to the file’s size). For example, 
       -M90% means git should consider a delete/add pair to be a rename if more than
       90% of the file hasn’t changed.
Zitrax
fonte
7
Lifesaver! Minhas diferenças de git são muito melhores agora. 1) É seguro usar sempre esta opção? 2) Posso adicionar esta opção como comportamento padrão ao meu ~/.gitconfig?
Kevinarpe
5
Observe que a detecção de renomeação funciona apenas quando os arquivos antigos e novos aparecem na coleção de arquivos processados ​​por git diff. A execução git diff -Mem um único arquivo (renomeado) não informa uma renomeação.
31417 Leon
1
Isso não funciona para mim, mas git log --follow -- file_after_move.txtfunciona bem. Ele mostra toda a história, inclusive antes da mudança. Alguma ideia? Estou executando git version 2.11.0.windows.1.
bouvierr
1
A -Copção para detectar cópias é útil e semelhante. Usei-o -Mpara olhar para um diff em que havia refatorado um arquivo em dois (sem nenhum nome correspondente ao original).
cp.engr 19/07/19
85

Além do que knittl escreveu , você sempre pode usar:

git diff HEAD:./oldfilename newfilename

onde HEAD:./oldfilenamesignifica oldfilename no último commit (em HEAD), relativo ao diretório atual.

Se você não tiver um git novo o suficiente, teria que usar:

git diff HEAD:path/to/oldfilename newfilename
Jakub Narębski
fonte
8
Obrigado por isso. Você também pode especificar um commit específico em vez de head, ou seja,git diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename
Chris Bloom
8
No caso, é claro, você também pode especificar nomes de filiais ou qualquer outra referência, tais como:git diff branch:old/filen.name newfilename
jricher
O primeiro formulário funciona para mim, se você cdpara o diretório e não adicionar --antes do commit:pathpar. O Git parece ser muito exigente com sintaxe aqui.
dhardy
1
@dhardy A <commit-ish>:<pathname>sintaxe é um identificador de objeto, algo como Git-ish; depois que o --Git espera apenas nomes de arquivos.
Jakub Narębski 29/11
18

Com o git 2.9 (junho de 2016), você não precisará -Mmais adicionar . git diffusa -Mpor padrão.

Consulte commit 5404c11 , commit 9501d19 , commit a9276a6 , commit f07fc9e , commit 62df1e6 (25 de fevereiro de 2016) por Matthieu Moy ( moy) .
(Mesclado por Junio ​​C Hamano - gitster- na confirmação 5d2a30d , 03 de abril de 2016)

diff: ativar diff.renamespor padrão

A detecção de renomeação é um recurso muito conveniente, e os novos usuários não precisam procurar na documentação para se beneficiar.

As possíveis objeções à ativação da detecção de renomeação são que, às vezes, falha e às vezes é lento. Mas a detecção de renomeação já está ativada por padrão em vários casos como " git status" e " git merge", portanto, a ativação diff.renamesnão altera fundamentalmente a situação. Quando a detecção de renomeação falha, ela agora falha consistentemente entre " git diff" e " git status".

Essa configuração não afeta os comandos de encanamento, portanto, scripts bem escritos não serão afetados.

Os novos testes para esse recurso estão aqui .

VonC
fonte
1

git diff -Mativa a detecção de renomeação como outros disseram (e como o @VonC apontou, ela é ativada por padrão no git 2.9). Mas se você tiver um grande conjunto de alterações, a detecção inexata de renomeação ainda poderá ser desativada novamente. O Git exibirá um aviso como o seguinte, fácil de perder em meio ao diff que você está visualizando:

warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 450 and retry the command.

Nesse caso, defina a opção de configuração conforme sugerido pelo git, por exemplo

git config diff.renamelimit 450

e execute novamente o seu comando diff.

mindriot
fonte
0

Por qualquer motivo, usar HEAD:./oldfilename(ou caminho absoluto) não funcionou para mim, mas HEAD:oldfilenamefuncionou (obrigado cmn):

git diff HEAD:oldfilename newfilename
git diff 2a80f45:oldfilename f65f3b3:newfilename

HTH

Oli Studholme
fonte
Talvez seu idiota seja velho demais para entender HEAD:./oldfilename?
Jakub Narębski
-4

simplesmente execute git diffsem argumentos, ou git diff -- newfilename. O git é inteligente o suficiente para comparar os arquivos / conteúdos corretos (ou seja, conteúdo original antes de renomear com conteúdo alterado após renomear)

knittl
fonte
2
O git não é absolutamente inteligente o suficiente na maioria dos casos. Simplesmente git mvinserir um único arquivo e comparar o estado faseado com outro ramo idêntico produzirá a diferença "tudo foi excluído e recriado novamente", a menos que -Mseja usado.
Reinderien