git diff переименовывает / перемещает и изменяет файлы, но пропускает переименованные / перемещенные и идентичные файлы
Я использую:
git diff HEAD --diff-filter=R -M
с помощью внешнего инструмента сравнения meld для отображения файлов, которые были переименованы / перемещены и изменены. Я всегда делаю git diff перед выполнением коммита, чтобы как проверить свою работу, так и правильно собрать сообщение коммита. Часто я буду переименовывать / перемещать файлы, что также потребует некоторых изменений пути в файлах, которые ссылаются на некоторые переименованные / перемещенные файлы.
Моя проблема заключается в том, что для отображения различий файла, который был переименован и затем изменен, git diff также выскакивает кучу окон слияния для файлов, которые были переименованы, но не изменены. Это может быть очень раздражающим. Как заставить git diff пропустить переименованные, но не измененные файлы? Я собираюсь увидеть все эти файлы, перечисленные как переименованные / перемещенные, когда я набираю git status более понятным способом, поэтому я не хочу, чтобы всплывающие окна идентичных файлов были с помощью git diff.
1 ответ
У меня та же проблема, и я нашел псевдоним, который добился цели (я использую git 2.8.3)
[alias]
difftoolr = "!git difftool \"$@\" -- . $((git diff \"$1\" -M100% --diff-filter=R --name-only & git diff \"$1\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"
Как пользоваться:
difftoolr commit1..commit2 -M
(см. внизу для большего количества примеров)
Как это устроено:
Представьте, что у вас есть три файла, которые были переименованы. У одного из них действительно изменился его контент (поэтому вы хотите проверить его с помощью difftool), но два других идентичны, за исключением пути или имени (и вы хотите их игнорировать).
(different) path/file.old -> newPath/file.new
(identical) path/fileB.old -> newPath/fileB.new
(identical) path/fileC.old -> newPath/fileC.new
Псевдоним генерирует спецификации пути, которые явно исключают fileB
а также fileC
то есть те файлы, которые, несмотря на переименование, имеют неизменное содержимое.
Другими словами, мы генерируем эти спецификации файлов:
-- . :(exclude)path/fileB.old :(exclude)newPath/fileB.new :(exclude)path/fileC.old :(exclude)newPath/fileC.new
Обратите внимание на (возможно, самую хитрую) часть: старый путь к файлу и новый путь к файлу должны быть явно исключены.
Для этого мы выдаем git diff
со следующими директивами:
-M100%
: следуйте переименованиям Это означает, что git предполагает, что было выполнено некоторое переименование, и будет учитывать эту информацию для парных сравнений. Порог составляет 100%, что указывает git учитывать переименованные файлы, которые имеют точно такое же содержимое, но не те, которые были изменены.--diff-filter=R
: перечислить только файлы, которые git считает переименованными, пропустить остальные.--names-only
: просто выведите имена файлов, никакой другой информации-R
: Задний ход. В одном фрагменте скрипта мы меняем порядок сравнения (сортировка по левому и правому краю), поэтому он также выведет старые имена файлов. Например,-R
директива перечисляет файлnewPath/fileB.new
какpath/fileB.old
,...sed...
: и наконец мы добавляем директиву об исключении:(exclude)
к началу всех имен файлов.
Для работы с другими делами я создал три разных псевдонима (не очень элегантно, я хотел бы что-то более гибкое), чтобы его можно было использовать для определения различных видов сравнения.
git difftoolr0 -M
git difftoolr1 HEAD~1..HEAD -M
git difftoolr2 HEAD --cached -M
Во всех случаях "стороны сравнений" (commitits, --cached или что-то еще) должны быть указаны в качестве первого параметра (ов). Например git difftoolr2 -M HEAD --cached
не будет работать (потому что -M
приходит первым).
[alias]
# takes no parameter: sample usage: git difftoolr0 -M
difftoolr0 = "!git difftool \"$@\" -- . $((git diff -M100% --diff-filter=R --name-only & git diff -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"
# takes 1 parameter in first position: sample usage: git difftoolr1 HEAD~1..HEAD -M
difftoolr1 = "!git difftool \"$@\" -- . $((git diff \"$1\" -M100% --diff-filter=R --name-only & git diff \"$1\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"
# takes 2 parameters in first positions: sample usage: git difftoolr2 HEAD --cached -M
difftoolr2 = "!git difftool \"$@\" -- . $((git diff \"$1\" \"$2\" -M100% --diff-filter=R --name-only & git diff \"$1\" \"$2\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"
Наконец, BeyondCompare может удовлетворить ваши потребности (и мои).
Это легко позволяет переключать параллельный дифференциал в "неструктурированный" дифференциал.
Последний снимает папки и оставляет только имена. Если имя файла совпадает (но пути могут отличаться), они считаются двумя версиями одного и того же файла (например, path/file.png
а также newPath/file.png
). В этом случае, если содержимое не изменилось, их можно легко опустить, используя кнопку на верхней панели.
В случае возникновения конфликтов "имен" (несколько файлов на одной стороне сравнения имеют одно и то же имя под разными путями), он выберет для сравнения только один из них и проигнорирует другие.