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

128

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

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

доктор Джерри
источник
4
Скоро (git 2.9, июнь 2016) простого git diff -- yourRenamedFileбудет достаточно. Смотрите мой ответ ниже
VonC

Ответы:

145

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

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

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

git diff HEAD:./oldfilename newfilename

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

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

git diff HEAD:path/to/oldfilename newfilename
Якуб Наребски
источник
8
Спасибо за это. Вы также можете указать конкретный коммит вместо заголовка, напримерgit diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename
Крис Блум,
8
Если что-то неясно, вы также можете указать названия веток или любую другую ссылку, например:git diff branch:old/filen.name newfilename
jricher
Первая форма у меня работает, если вы cdв каталог и не добавляете --перед commit:pathпарой. Здесь Git очень разборчив с синтаксисом.
dhardy
1
@dhardy <commit-ish>:<pathname>Синтаксис - это идентификатор объекта, что-то в стиле Git; после того, как --Git ожидает только имена файлов.
Якуб Наребски
18

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

См. Коммит 5404c11 , фиксация 9501d19 , фиксация a9276a6 , фиксация f07fc9e , фиксация 62df1e6 (25 февраля 2016 г.) от Matthieu Moy ( moy) .
(Объединено Junio ​​C Hamano - gitster- в фиксации 5d2a30d , 3 апреля 2016 г.)

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

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

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

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

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

VonC
источник
1

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

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.

mindriot
источник
0

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

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

НТН

Оли Studholme
источник
Возможно, ваш мерзавец слишком стар для понимания HEAD:./oldfilename?
Якуб Наребски 01
-4

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

knittl
источник
2
git в большинстве случаев абсолютно недостаточно умен. Простая git mvвставка одного файла и последующее сравнение поэтапного состояния с другой идентичной в остальном ветвью приведет к различию «все было удалено и воссоздано заново», если -Mоно не используется.
Reinderien