git diff перейменований файл


105

У мене є файл a.txt.

cat a.txt
> hello

Вміст a.txt"привіт".

Я беру на себе зобов’язання.

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

Потім я переходжу a.txtв testдір.

mkdir test
mv a.txt test

Тоді я беру свій другий вчинок.

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

Нарешті, я редагую, a.txtщоб сказати "до побачення".

cat a.txt
> goodbye

Я беру свій останній вчинок.

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

Тепер ось моє питання:

Як я відрізняю зміст a.txtміж моїм останнім чином і першим вчиненням?

Я спробував:, git diff HEAD^^..HEAD -M a.txtале це не вийшло. git log --follow a.txtналежним чином виявляє перейменування, але я не можу знайти еквівалент для git diff. Є такий?


Я вважаю, що це було б так само, якби ви зробили тест "git mv a.txt"? IE ви просто перейменували файл замість того, щоб переміщувати його у підкаталог.
Макс Вотерман

Відповіді:


107

Різниця між різницею HEAD^^та HEADполягає в тому, що у вас є a.txtобидва коміти, тож, враховуючи ці два коміти (що є різницею), перейменування немає, є копія та зміна.

Для виявлення копій можна скористатися -C:

git diff -C HEAD^^ HEAD

Результат:

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

До речі, якщо ви обмежите свій розріз лише одним шляхом (як ви це робите, git diff HEAD^^ HEAD a.txtви ніколи не збираєтеся бачити перейменування чи копії, тому що ви виключили все, окрім одного шляху, а перейменування чи копії - за визначенням - залучайте два стежки.


2
Скажімо, комісія містила кілька змін файлів. Як би я звузив його до відмінності одного файлу?
Кен Хіракава

3
@KenHirakawa використання -- <old-path> <new-path>... дивіться мою відповідь.
Нолан Емі

У моєму випадку я хотів показати подробиці комісії, де файл був перейменований, але він просто показував мені, що файл видалено та додано файл ... Я побіг, git show -C [commit]і він розпізнав перейменування файлу і показав мені різниться між файлами. Ідеально.
Джейсон

83

Щоб відрізнятись від перейменування певного файлу, використовуйте -M -- <old-path> <new-path>( -Cтакож працює).

Отже, якщо ви перейменували та змінили файл в останньому комітеті, ви можете побачити зміни за допомогою:

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

Це дає:

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.txtрядки додані, щоб допомогти git виявити перейменування)


Якщо git не визначає перейменування, ви можете вказати низький поріг подібності -M[=n], скажімо, 1%:

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

З git diff docs :

-M [<n>] - знайти-перейменує [= <n>]

Виявити перейменування. Якщо nвказано, це поріг по індексу подібності (тобто кількість додавання / видалення порівняно з розміром файлу). Наприклад, -M90%засоби Git повинні вважати пару видалення / додавання перейменуванням, якщо більше 90% файлу не змінилося. Без %знака число слід читати як дріб, з десятковою точкою перед ним. Тобто -M5стає 0,5, і, таким чином, те саме, що -M50%. Точно так само, -M05як -M5%. Щоб обмежити виявлення точними перейменами, використовуйте -M100%. Індекс схожості за замовчуванням - 50%.


... Звичайно, також працює, коли зміни та перейменування знаходяться в окремих комісіях, як у оригінальному прикладі:git diff HEAD^^ HEAD -M -- a.txt test/a.txt
Нолан Емі

1
Тільки тоді, коли вміст файлів достатньо близький, щоб розрізник міг придумати індекс подібності. Використання обох параметрів (-M та -C) показує відмінності / dev / null від / dev / null у файлі, який було перейменовано та повністю змінено (включаючи відступ), він навіть не вловлює його при ігноруванні пробіл.
DavidG

37

Ви також можете зробити:

git diff rev1:file1 rev2:file2

який, для вашого прикладу, був би

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

Зверніть увагу на явне ./- цей формат інакше передбачає, що шляхи мають відношення до кореня репо. (Якщо ви знаходитесь в корені репо, ви можете, звичайно, пропустити це.)

Це взагалі не залежить від виявлення перейменування, оскільки користувач прямо заявляє, з чим саме порівнювати. (Тому це також стане в нагоді в деяких інших обставинах, наприклад, порівнянні файлів між різними гілками svn у середовищі git-svn.)


1
Ооо, це приємно!
Нолан Емі

Для перейменування з додатковими змінами файлів, внесеними через об'єднання, це єдина відповідь, яка працювала на мене. Дякую!
Лейн Реттіг

1

Якщо ваше перейменування здійснюється поетапно, але ще не здійснено, ви можете використовувати:

git diff --cached -M -- file.txt renamed_file.txt
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.