Как git обнаруживает похожие файлы для обнаружения переименования?

Википедия объясняет автоматическое обнаружение переименования:

Вкратце, учитывая файл в редакции N, файл с тем же именем в Версия N-1 является ее предшественником по умолчанию. Однако, когда нет файл с именем в версии N-1, Git выполняет поиск файла, который существует только в редакции N-1 и очень похоже в новый файл.

Переименовать обнаружение, по-видимому, сводится к аналогичному обнаружению файлов. Этот алгоритм документирован где угодно? Было бы неплохо узнать, какие виды преобразований обнаруживаются автоматически.

Ответ 1

Git отслеживает содержимое файла, а не имена файлов. Таким образом, переименование файла без изменения его содержимого легко обнаружить git. (Git не отслеживает, но выполняет обнаружение; использование git mv или git rm и git add фактически одинаково.)

Когда файл добавляется в репозиторий, имя файла находится в дереве. Фактическое содержимое файла добавляется в виде двоичного большого объекта (blob) в репозитории. git не добавит еще одного blob для дополнительных файлов, содержащих один и тот же контент. Фактически, git не может, поскольку содержимое хранится в файловой системе, причем первые два символа хэша являются именем каталога, а остальное - именем файла внутри него. Таким образом, для обнаружения переименований речь идет о сравнении хэшей.

Чтобы обнаружить небольшие изменения в переименованном файле, git использует определенные алгоритмы и пороговое ограничение, чтобы увидеть, является ли это переименованием. Например, обратите внимание на флаг -M для git diff. Существуют также значения конфигурации, такие как merge.renameLimit (количество файлов, которые следует учитывать при выполнении определения переименования во время слияния).

Чтобы понять, как git обрабатывает похожие файлы (то есть, какие преобразования файлов рассматриваются как переименования), изучите параметры конфигурации и доступные флаги, как упоминалось выше. Вам не следует учитывать, как это сделать. Чтобы понять, как git выполняет эти задачи, посмотрите алгоритмы поиска различий в тексте и прочитайте исходный код git.

Алгоритмы применяются только для целей diff, merge и log - они не влияют на то, как git хранит их. Любое небольшое изменение в содержимом файла означает, что для него добавляется новый объект. На этом уровне нет дельта или разницы. Конечно, позже, объекты могут быть упакованы, где дельта хранится в packfiles, но это не связано с обнаружением переименования.

Ответ 2

Существует множество алгоритмов, которые обнаруживают сходство между текстами, а системы контроля версий часто используют их уже для хранения только разницы между двумя версиями. Такие инструменты, как WinMerge, достаточно умны, чтобы обнаруживать различия даже внутри строк, поэтому я не вижу причин, по которым эти алгоритмы не использовались для этого обнаружения переименования.

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