Как сделать git diff для перемещенного/переименованного файла?

Я переместил файл с помощью git mv. Теперь я хотел бы сделать diff для нового файла, чтобы сравнить его со старым файлом (со старым, теперь несуществующим именем).

Как мне это сделать?


person dr jerry    schedule 20.04.2011    source источник
comment
Вскоре (git 2.9, июнь 2016 г.) будет достаточно простого git diff -- yourRenamedFile. См. мой ответ ниже   -  person VonC    schedule 05.04.2016


Ответы (6)


Вам нужно использовать -M, чтобы позволить git автоматически определять перемещенный файл при сравнении. Использование только git diff, как уже упоминалось, мне не подходит.

Так просто: git diff -M должен это сделать.

Документация для этого коммутатора:

-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.
person Zitrax    schedule 12.04.2012
comment
Спасатель! Мои git diffs теперь намного лучше. 1) Безопасно ли всегда использовать эту опцию? 2) Могу ли я добавить эту опцию в качестве поведения по умолчанию для моего ~/.gitconfig? - person kevinarpe; 15.11.2015
comment
Обратите внимание, что обнаружение переименования работает только в том случае, если в коллекции файлов, обработанных git diff, присутствуют как старые, так и новые файлы. Запуск git diff -M для одного (переименованного) файла не сообщает о переименовании. - person Leon; 25.10.2017
comment
Это не работает для меня, но git log --follow -- file_after_move.txt работает хорошо. Показывает всю историю, в том числе до переезда. Любые идеи? Я бегу git version 2.11.0.windows.1. - person bouvierr; 04.05.2018
comment
Опция -C для обнаружения копий полезна и похожа. Я использовал его с -M для просмотра разницы, в которой я реорганизовал один файл в два (ни одно имя не соответствует оригиналу). - person cp.engr; 19.07.2018

В дополнение к тому, что написал knittl, вы всегда можете использовать:

git diff HEAD:./oldfilename newfilename

где HEAD:./oldfilename означает старое имя файла в последнем коммите (в HEAD) относительно текущего каталога.

Если у вас нет достаточно нового git, вместо этого вам придется использовать:

git diff HEAD:path/to/oldfilename newfilename
person Jakub Narębski    schedule 20.04.2011
comment
Спасибо за это. Вы также можете указать конкретный коммит вместо головы, т.е. git diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename - person Chris Bloom; 29.02.2012
comment
Если что-то неясно, вы также можете указать названия веток или любую другую ссылку, например: git diff branch:old/filen.name newfilename - person jricher; 25.09.2013
comment
У меня работает первая форма, если cd в директорию и не добавлять -- перед парой commit:path. Git, похоже, очень придирчив к синтаксису. - person dhardy; 28.11.2016
comment
@dhardy Синтаксис <commit-ish>:<pathname> - это идентификатор объекта, что-то вроде Git-ish; после -- Git ожидает только имена файлов. - person Jakub Narębski; 30.11.2016
comment
Этот синтаксис работал для меня, где -M просто показывал весь файл как измененный - git version 2.30.1 (Apple Git-130). Это работало с ведущим ./ или без него. - Спасибо. - person Ed Randall; 23.06.2021

С git 2.9 (июнь 2016 г.) вам больше не нужно будет добавлять -M. git diff по умолчанию использует -M.

См. коммит 5404c11, фиксация 9501d19, фиксация a9276a6, зафиксировать f07fc9e, 1 зафиксировать Матье Мой (moy).
(объединено Junio ​​C Hamano -- gitster -- в commit 5d2a30d, 3 апреля 2016 г.)

diff: активировать diff.renames по умолчанию

Обнаружение переименования — очень удобная функция, и новым пользователям не нужно копаться в документации, чтобы воспользоваться ею.

Потенциальные возражения против активации обнаружения переименования заключаются в том, что иногда оно не работает, а иногда работает медленно. Но определение переименования уже включено по умолчанию в нескольких случаях типа "git status" и "git merge", так что включение diff.renames принципиально ситуацию не меняет. Когда обнаружение переименования завершается сбоем, теперь оно последовательно терпит неудачу между «git diff» и «git status».

Этот параметр не влияет на команды сантехники, поэтому он не повлияет на хорошо написанные скрипты.

Новые тесты для этой функции здесь.

person VonC    schedule 05.04.2016

По какой-то причине использование HEAD:./oldfilename (или абсолютного пути) у меня не сработало, а HEAD:oldfilename сработало (спасибо, cmn):

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

ХТН

person Oli Studholme    schedule 26.12.2011
comment
Возможно, ваш гит слишком стар, чтобы понять HEAD:./oldfilename? - person Jakub Narębski; 01.03.2012

git diff -M активирует обнаружение переименования, как говорили другие (и, как указал @VonC, он активируется по умолчанию из git 2.9). Но если у вас большой набор изменений, обнаружение неточного переименования может снова отключиться. Git отобразит предупреждение, подобное следующему, которое легко пропустить среди просматриваемого вами diff:

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.

В этом случае установите параметр конфигурации, предложенный git, например

git config diff.renamelimit 450

и повторно запустите команду diff.

person mindriot    schedule 09.10.2018

просто запустите git diff без аргументов или git diff -- newfilename. git достаточно умен, чтобы сравнивать правильные файлы/содержимое (т. е. исходное содержимое до переименования с измененным содержимым после переименования)

person knittl    schedule 20.04.2011
comment
git абсолютно недостаточно умен в большинстве случаев. Простое git mv создание одного файла, а затем сравнение промежуточного состояния с другой идентичной в остальном веткой приведет к тому, что все было удалено и воссоздано снова, если не используется -M. - person Reinderien; 12.05.2015