Как запустить Git diff и показать новое местоположение перемещенного файла вместо старого? - PullRequest
0 голосов
/ 24 апреля 2019

Я использую следующую команду: git --no-pager diff --name-only 'origin/oldbranch'..'origin/newerbranch'

Это прекрасно работает, я получаю список всех файлов, которые были изменены, удалены или добавлены со времен oldbranch.

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

Похоже, нелегко сделать так, чтобы git diff сообщал мне новое местоположение файла. Кажется, я должен использовать git log --name-only -- "**/themovedfile.txt", чтобы вернуть все результаты, где этот файл существовал. Хотя я мог бы написать некоторую логику, чтобы справиться с этим, это кажется излишним.

Есть ли более простой способ сделать это?

1 Ответ

1 голос
/ 25 апреля 2019

Здесь есть пара примечательных вещей, но давайте начнем с ответа:

git diff --name-only L R

сравнивает два конкретных коммита, используя ваши настроенные значения по умолчанию (например, diff.renames и diff.renameLimit`), и выдает только имена файлов, которые отличаются коммитами L (слева) и R (справа). Если вы поменяете местами два имени, вы получите одинаковый вывод. Если обнаружение переименования действует, вы получаете имя, которое появляется в коммите R:

$ git diff 99177b34db^ 99177b34db --name-only
contrib/hooks/multimail/CHANGES
contrib/hooks/multimail/CONTRIBUTING.rst
contrib/hooks/multimail/README.Git
contrib/hooks/multimail/README.rst
contrib/hooks/multimail/doc/gitolite.rst
contrib/hooks/multimail/git_multimail.py
contrib/hooks/multimail/migrate-mailhook-config
contrib/hooks/multimail/post-receive.example

Переключение на --name-status дает нам больше информации:

$ git diff 99177b34db^ 99177b34db --name-status
M       contrib/hooks/multimail/CHANGES
M       contrib/hooks/multimail/CONTRIBUTING.rst
M       contrib/hooks/multimail/README.Git
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst
M       contrib/hooks/multimail/doc/gitolite.rst
M       contrib/hooks/multimail/git_multimail.py
M       contrib/hooks/multimail/migrate-mailhook-config
M       contrib/hooks/multimail/post-receive.example

Статус R указывает, что Git обнаружил переименование. Теперь вы получаете оба имени: слева от L , а справа от R .

Двухточечная запись

Здесь я написал 99177b34db^ 99177b34db вместо 99177b34db^..99177b34db. Во многих командах Git они очень разные. Но для команды diff они означают точно то же самое . Нет никаких оснований для использования двух точек, но также нет никаких причин для избегания двух точек. Правила для имен веток запрещают две соседние точки: имена веток, такие как feature.one и feature.two, являются законными, но feature..two - нет.

(Не путайте двухточечную запись с трехточечной. Это также имеет особое значение в git diff.)

Фиксация хэшей против имен ветвей

Я использовал 99177b34db вместо имени ветви. Вы писали:

origin/oldbranch..origin/newerbranch

(одинарные кавычки здесь не нужны, поэтому я удалил их для простоты). Во многих командах Git имя ветки означает то же самое, что и идентификатор хеша коммита, к которому оно относится:

$ git rev-parse master
b5101f929789889c2e536d915698f58d5c5c6b7a

Вы можете использовать необработанный хэш-идентификатор или его сокращенную форму для обозначения этого конкретного коммита. Причина использования ветви name заключается в том, что идентификатор хеша фиксации, идентифицируемый с помощью , меняется с течением времени по мере добавления новых фиксаций в ветку. Идентификаторы в основном бесполезны для людей, а имена создаются людьми и для людей.

(Некоторые команды, такие как git checkout, делают с именем что-то более интересное, поэтому для этих команд имя не взаимозаменяемо с хеш-идентификатором.)

Обнаружение переименования является опцией

То, что делает git diff, сравнивает два снимка . Каждый коммит представляет собой полный, полный снимок каждого исходного файла. Git берет левый коммит и правый и сравнивает их. Для файлов, которые находятся в обоих коммитах и ​​одинаковы в обоих коммитах, git diff ничего не говорит. Для файлов, которые отличаются или находятся только в одном коммите или другом, git diff что-то говорит.

С --name-only то, что он говорит, - это имя (имена) файла (ов) в R , которые отличаются. С --name-status он дает имена и , что отличало их: они могут быть изменены, т. Е. Представлены в обоих коммитах, но с другим содержимым, или добавлены заново, т. Е. В коммите R * Только 1082 * или удалено, т. Е. В коммите L только.

Когда вы включаете обнаружение переименования, если какой-либо файл удаляется в L , а в R создается * файл с другим именем, git diff делает кучу дополнительных вычислений, чтобы решить действительно ли новый файл в R"совпадает" с файлом в L . Эта концепция одинаковости - или идентичность (см. https://en.wikipedia.org/wiki/Ship_of_Theseus)—is, на самом деле довольно сложная, хотя Git дает простой и непостижимый ответ: два файла одинаковы, если Git вычисляет индекс подобия соответствует некоторому пороговому значению. По умолчанию установлено значение «50% похоже».

Буквенный код для обнаруженного переименования: R; за этим следует индекс сходства. Чем выше индекс, тем более похожи файлы. 100 зарезервировано для точно такого же , что является чем-то особенным в Git: если два файла абсолютно одинаковы, они на самом деле хранятся только один раз , и Git может обнаружить это точное совпадение очень быстро.

Если обнаружение переименования отключено, вы просто удалите файл из L и файл с другим именем добавлен в R , даже если два файла являются побитовымиидентичны.Поскольку обнаружение переименования является элементом конфигурации, два разных пользователя, выполняющих git diff на одних и тех же двух коммитах, могут видеть разные результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...