получить полный путь к файлу до и после переименования файла в git log - PullRequest
1 голос
/ 23 апреля 2019

Предположим, я знаю, что файл был переименован (переименование может произойти путем переименования имени файла или перемещения файла в другой каталог) в определенный коммит.git show --summary <sha> показывает все случаи такого переименования в коммите.Однако, git только отмечает разницу между старым и новым filepath.Ниже приведены два примера -

rename xbmc/interfaces/{ => builtins}/Builtins.cpp (100%)
rename xbmc/cores/AudioEngine/Engines/ActiveAE/{ActiveAEResample.cpp => ActiveAEResampleFFMPEG.cpp} (100%)

Как эффективно проанализировать полный путь к файлу до и после переименования, как это можно сделать разными способами?Или есть другая команда git, которая показывает эту информацию более простым способом?

1 Ответ

2 голосов
/ 23 апреля 2019

TL; DR

Учитывая, что вы знаете хеш коммита <hash>, вы, вероятно, захотите:

git diff-tree --find-renames -r --name-status --diff-filter=R --no-commit-id <hash>

или то же самое с добавлением -z. Вы также можете указать (первого) родителя слияния, в этом случае --no-commit-id не требуется.

Long

Есть несколько способов сделать это в зависимости от различных деталей о том, что вы хотите для вывода. Ключ должен начинаться с предсказуемой команды plumbing . В Git сантехническая команда - это команда, которая по существу предназначена для использования какой-либо другой программой, так что она имеет машиночитаемый, предсказуемый, надежный формат вывода. Теперь вы получаете вывод git diff --summary, а git diff - команду фарфор , предназначенную для чтения человеком:

$ git diff --summary 99177b34db^ 99177b34db
 rename contrib/hooks/multimail/{README => README.rst} (95%)

, который git show --summary выполняется в конце других своих операций.

Для механически разбираемого вывода мы можем переключиться на git diff-tree. Если нам нужны имена и статусы каждого измененного файла, мы можем запросить это:

$ git diff-tree --name-status -r 99177b34db^ 99177b34db
M       contrib/hooks/multimail/CHANGES
M       contrib/hooks/multimail/CONTRIBUTING.rst
D       contrib/hooks/multimail/README
M       contrib/hooks/multimail/README.Git
A       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

Мы сразу видим, что здесь есть недостаток: мы не наблюдали переименования. Это связано с тем, что между (первым и единственным) родителем коммита 99177b34db (99177b34db^) и самого коммита 99177b34db фактического переименования не было. Два снимка имеют только два набора файлов. Переименование, которое мы видим, является догадкой , которое git diff --summary делает. Чтобы поручить Git делать то же предположение при использовании git diff-tree, мы должны добавить --find-renames - что позволяет us выбрать порог сходства, который считается переименованием, но по умолчанию равен тем же 50%, которые мы получаем за резюме:

$ git diff-tree --find-renames --name-status -r 99177b34db^ 99177b34db
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

Эта строка R095 содержит то, что мы хотим: обнаруженное переименование, значение сходства (в данном случае 95%) и оба имени файла, в данном случае разделенные табуляцией.

Мы можем использовать --diff-filter, чтобы уменьшить вывод и включить только переименования:

$ git diff-tree --find-renames --name-status -r --diff-filter=R 99177b34db^ 99177b34db
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

Обратите внимание, что мы можем запустить git diff-tree только с одним хэшем коммита. Это хорошо работает, когда коммит является обычным (без слияния):

$ git diff-tree --find-renames --name-status -r --diff-filter=R 99177b34db
99177b34db1d473e8f90544cf0bf83f47308e9ad
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

Однако теперь мы получаем полный идентификатор хэша в выводе. Добавление --no-commit-id говорит, что он не должен включать хеш-код.

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

Отбрасывание --name-status дает нам этот другой формат, более длинный и иногда более полезный:

$ git diff-tree --find-renames -r --diff-filter=R 99177b34db^ 99177b34db
:100644 100644 5105373aea044f2d8fde0c4fd927c8c492d02585 7c0fc4a6ef00362dcff476497a6045a420562d05 R095   contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

Здесь мы получаем хэши BLOB-объектов двух файлов с двумя режимами (100644) перед ними, все с префиксом одного двоеточия :. Детали изменились бы, если бы мы получили вывод для коммита слияния.

Во всех этих случаях вы можете добавить опцию -z. Это изменяет выходные данные, чтобы сделать их еще более машиночитаемыми (но очень нечитаемыми человеком): различные части каждой выходной записи имеют байты ASCII NUL (0x00) для их разделения. Эта опция также описана в документации вместе с некоторыми подробностями того, какие изменения вносятся в имена путей, когда вы не используете -z.

...