git diff mengganti nama file

105

Saya punya file a.txt.

cat a.txt
> hello

Isi dari a.txtis "hello".

Saya membuat komitmen.

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

Saya kemudian pindah a.txtke testdir.

mkdir test
mv a.txt test

Saya kemudian membuat komitmen kedua saya.

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

Akhirnya, saya mengedit a.txtuntuk mengucapkan "selamat tinggal" sebagai gantinya.

cat a.txt
> goodbye

Saya membuat komitmen terakhir saya.

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

Sekarang inilah pertanyaan saya:

Bagaimana cara saya membedakan konten a.txtantara komit terakhir dan komit pertama saya?

Saya sudah mencoba:, git diff HEAD^^..HEAD -M a.txttetapi tidak berhasil. git log --follow a.txtmendeteksi penggantian nama dengan benar, tetapi saya tidak dapat menemukan padanan untuk git diff. Apakah ada?

Ken Hirakawa
sumber
Saya kira itu akan sama jika Anda melakukan 'tes git mv a.txt'? IE Anda baru saja mengganti nama file, bukan memindahkannya ke subdirektori.
Max Waterman

Jawaban:

107

Masalah dengan perbedaan antara HEAD^^dan HEADapakah Anda memiliki filea.txt di kedua komit, jadi hanya dengan mempertimbangkan dua komit tersebut (yang dilakukan diff), tidak ada penggantian nama, ada salinan dan perubahan.

Untuk mendeteksi salinan, Anda dapat menggunakan -C:

git diff -C HEAD^^ HEAD

Hasil:

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

Kebetulan, jika Anda membatasi diff hanya pada satu jalur (seperti yang Anda lakukan di git diff HEAD^^ HEAD a.txtAnda tidak akan pernah melihat penggantian nama atau salinan karena Anda telah mengecualikan semuanya selain dari satu jalur dan mengganti nama atau salinan - menurut definisi - melibatkan dua jalur.

CB Bailey
sumber
2
Katakanlah komit berisi beberapa perubahan file. Bagaimana saya mempersempitnya menjadi diff dari satu file?
Ken Hirakawa
3
@KenHawa gunakan -- <old-path> <new-path>... lihat jawaban saya.
Nolan Amy
Dalam kasus saya, saya ingin menunjukkan detail komit di mana file itu diganti namanya, tetapi itu hanya menunjukkan kepada saya bahwa file telah dihapus dan file ditambahkan ... Saya menjalankan git show -C [commit]dan itu mengenali file yang diganti namanya dan menunjukkan kepada saya perbedaan antar file. Sempurna.
Jason
83

Untuk membedakan mengubah nama file tertentu, gunakan -M -- <old-path> <new-path>( -Cjuga berfungsi).

Jadi jika Anda berdua mengganti nama dan mengubah file di komit terakhir, Anda dapat melihat perubahannya dengan:

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

Ini menghasilkan:

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.txtbaris ditambahkan untuk membantu git mendeteksi penggantian nama)


Jika git tidak mendeteksi penggantian nama, Anda dapat menentukan ambang kesamaan rendah dengan -M[=n], katakanlah 1%:

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

Dari dokumen git diff :

-M [<n>] --temukan-ganti nama [= <n>]

Deteksi penggantian nama. Jika nditentukan, itu adalah ambang pada indeks kesamaan (yaitu jumlah penambahan / penghapusan dibandingkan dengan ukuran file). Sebagai contoh, -M90%berarti Git harus mempertimbangkan pasangan delete / add untuk mengganti nama jika lebih dari 90% file tidak berubah. Tanpa %tanda, bilangan tersebut dibaca sebagai pecahan, dengan titik desimal di depannya. Yaitu, -M5menjadi 0,5, dan dengan demikian sama dengan -M50%. Sama halnya -M05dengan -M5%. Untuk membatasi deteksi ke penggantian nama yang tepat, gunakan -M100%. Indeks kesamaan default adalah 50%.

Nolan Amy
sumber
... Tentu saja, juga berfungsi saat perubahan dan penggantian nama dilakukan secara terpisah seperti pada contoh asli:git diff HEAD^^ HEAD -M -- a.txt test/a.txt
Nolan Amy
1
Hanya jika isi dari file-file tersebut cukup dekat untuk diff untuk menghasilkan indeks kesamaan. Menggunakan kedua opsi (-M dan -C) menunjukkan perbedaan ke / dev / null an dari / dev / null dalam file yang telah diganti namanya dan telah berubah seluruhnya (termasuk inden bijaksana), bahkan tidak menangkapnya saat mengabaikan spasi.
DavidG
37

Anda juga bisa melakukan:

git diff rev1:file1 rev2:file2

yang, untuk contoh Anda, adalah

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

Perhatikan eksplisitnya ./ - format ini jika tidak mengasumsikan jalur menjadi relatif terhadap root repo. (Jika Anda berada di root repo, tentu saja Anda dapat mengabaikannya.)

Ini sama sekali tidak bergantung pada deteksi penggantian nama, karena pengguna secara eksplisit menyatakan apa yang harus dibandingkan. (Oleh karena itu, ini juga berguna dalam beberapa keadaan lain, seperti membandingkan file antara cabang svn yang berbeda di lingkungan git-svn.)

benkc
sumber
1
Oooh, ini bagus!
Nolan Amy
Untuk mengganti nama dengan perubahan file tambahan yang dibawa melalui gabungan, ini adalah satu-satunya jawaban yang berhasil untuk saya. Terima kasih!
Lane Rettig
1

Jika pengubahan nama Anda dilakukan bertahap tetapi belum dilakukan, Anda dapat menggunakan:

git diff --cached -M -- file.txt renamed_file.txt
Mr-IDE
sumber