git diff rinominato file


105

Ho un file a.txt.

cat a.txt
> hello

Il contenuto di a.txtè "ciao".

Mi impegno.

git add a.txt
git commit -m "first commit"

Poi mi sposto a.txtin una testdir.

mkdir test
mv a.txt test

Quindi faccio il mio secondo impegno.

git add -A
git commit -m "second commit"

Infine, modifico a.txtper dire "arrivederci" invece.

cat a.txt
> goodbye

Faccio il mio ultimo impegno.

git add a.txt
git commit -m "final commit"

Ora ecco la mia domanda:

Come faccio a diffondere il contenuto a.txttra il mio ultimo commit e il mio primo commit?

Ho provato:, git diff HEAD^^..HEAD -M a.txtma non ha funzionato. git log --follow a.txtrileva correttamente la ridenominazione, ma non riesco a trovare un equivalente per git diff. Ce n'è uno?


Suppongo che sarebbe lo stesso se facessi un 'git mv a.txt test'? Ad esempio, hai appena rinominato il file invece di spostarlo in una sottodirectory.
Max Waterman

Risposte:


107

Il problema con la differenza tra HEAD^^e HEADè che hai un a.txtcommit in entrambi i commit, quindi solo considerando quei due commit (che è ciò che fa diff), non c'è ridenominazione, c'è una copia e una modifica.

Per rilevare le copie, puoi utilizzare -C:

git diff -C HEAD^^ HEAD

Risultato:

index ce01362..dd7e1c6 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1 @@
-hello
+goodbye
diff --git a/a.txt b/test/a.txt
similarity index 100%
copy from a.txt
copy to test/a.txt

Per inciso, se restringi il tuo diff a un solo percorso (come fai in git diff HEAD^^ HEAD a.txtnon vedrai mai le rinomine o le copie perché hai escluso tutto tranne un singolo percorso e le ridenominazioni o le copie - per definizione - coinvolgono due percorsi.


2
Diciamo che il commit conteneva più modifiche ai file. Come potrei restringerlo a una differenza di un singolo file?
Ken Hirakawa

3
@KenHirakawa usa -- <old-path> <new-path>... guarda la mia risposta.
Nolan Amy

Nel mio caso, volevo mostrare i dettagli di un commit in cui il file è stato rinominato, ma mi stava solo mostrando che un file è stato cancellato e un file è stato aggiunto ... Sono corso git show -C [commit]e ha riconosciuto il file rinominato e mi ha mostrato il diff tra i file. Perfetto.
Jason

83

Per diffondere attraverso la ridenominazione di un file specifico, usa -M -- <old-path> <new-path>( -Cfunziona anche).

Quindi, se hai rinominato e modificato un file nell'ultimo commit, puoi vedere le modifiche con:

git diff HEAD^ HEAD -M -- a.txt test/a.txt

Questo produce:

diff --git a/a.txt b/test/a.txt
similarity index 55%
rename from a.txt
rename to test/a.txt
index 3f855b5..949dd15 100644
--- a/a.txt
+++ b/test/a.txt
@@ -1,3 +1,3 @@
 // a.txt

-hello
+goodbye

( // a.txtrighe aggiunte per aiutare git a rilevare la ridenominazione)


Se git non rileva la ridenominazione, puoi specificare una soglia di somiglianza bassa con -M[=n], diciamo 1%:

git diff HEAD^ HEAD -M01 -- a.txt test/a.txt

Dai documenti diff di git :

-M [<n>] --find-renames [= <n>]

Rileva le ridenominazioni. Se nè specificato, è una soglia sull'indice di somiglianza (cioè quantità di aggiunte / eliminazioni rispetto alla dimensione del file). Ad esempio, -M90%significa che Git dovrebbe considerare una coppia elimina / aggiungi come una ridenominazione se più del 90% del file non è stato modificato. Senza %segno, il numero va letto come frazione, preceduto da un punto decimale. Vale a dire, -M5diventa 0,5, ed è quindi uguale a -M50%. Allo stesso modo, -M05è lo stesso di -M5%. Per limitare il rilevamento a ridenominazioni esatte, utilizzare -M100%. L'indice di somiglianza predefinito è del 50%.


... Naturalmente, funziona anche quando la modifica e la rinomina sono in commit separati come nell'esempio originale:git diff HEAD^^ HEAD -M -- a.txt test/a.txt
Nolan Amy

1
Solo quando il contenuto dei file è abbastanza vicino da consentire a diff un indice di somiglianza. L'uso di entrambe le opzioni (-M e -C) mostra il diff a / dev / null e da / dev / null in un file che è stato rinominato ed è stato completamente cambiato (incluso il rientro), non lo cattura nemmeno quando lo ignora spazi bianchi.
DavidG

37

Puoi anche fare:

git diff rev1:file1 rev2:file2

quale, per il tuo esempio, sarebbe

git diff HEAD^^:./a.txt HEAD:./test/a.txt

Nota l'esplicito ./ : questo formato altrimenti presuppone che i percorsi siano relativi alla radice del repository. (Se sei nella radice del repo, puoi ovviamente ometterlo.)

Ciò non dipende affatto dal rilevamento della ridenominazione, poiché l'utente dichiara esplicitamente cosa confrontare. (Pertanto, è utile anche in alcune altre circostanze, come il confronto di file tra diversi rami svn in un ambiente git-svn.)


1
Oooh, questo è carino!
Nolan Amy

Per una ridenominazione con modifiche ai file aggiuntive apportate tramite un'unione, questa è l'unica risposta che ha funzionato per me. Grazie!
Lane Rettig

1

Se il commit di ridenominazione è stato messo in scena ma non è ancora stato eseguito il commit, puoi utilizzare:

git diff --cached -M -- file.txt renamed_file.txt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.