Как Git отслеживает историю во время рефакторинга? - PullRequest
17 голосов
/ 19 августа 2010

Я хорошо понимаю, как Git может поддерживать перемещение файлов: поскольку он использует хэш файла, «добавленный» файл легко определяется как «удаленный».

Мой вопрос касается рефакторинга: учитываяJava, объявление пакета изменяется, поэтому содержимое файла НЕ будет таким же.В таком случае, как Git определяет, что «добавленный» файл делится историей с «удаленным»?Проверяет ли «наиболее похожий контент», предполагая, что я внес только незначительные изменения или подобное недетерминированное решение?

1 Ответ

20 голосов
/ 19 августа 2010

Как упоминалось в Git FAQ , он будет обнаруживать похожий контент на основе эвристики.

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

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

Однако это не означает, что Git не поддерживает переименования.
Механизм сравнения в Git поддерживает автоматическое определение переименований, это включается переключателем '-M' для семейства команд git-diff-*.
Механизм обнаружения переименования используется git-log (1) и git-whatchanged (1) , поэтому, например, 'git log -M' выдаст историю коммитов с информацией о переименовании.
Git также поддерживает ограниченную форму слияния между переименованиями.
Два инструмента для назначения обвинений git-blame(1) и git-annotate(1) оба используют код обнаружения автоматического переименования для отслеживания переименований.


git log дает вам некоторые подробности об этой эвристике:

-B[<n>][/<m>]

Разбить полный переписать изменения на пары удаления и создания. Это служит двум целям:

  • Это влияет на то, как изменение, которое равняется общему перезаписи файла, не в виде последовательности удаления и вставки, смешанной вместе с очень небольшим количеством строк, которые текстуально соответствуют контексту, а как одно удаление всего старого с последующей единственной вставкой всего нового, и число m управляет этим аспектом опции -B (по умолчанию 60%).
    -B / 70% указывает, что менее 30% оригинала должно остаться в результате, чтобы git считал его полным перезаписью (т. Е. В противном случае полученный патч будет серией удаления и вставки, смешанных вместе с контекстные строки).

  • При использовании с -M полностью переписанный файл также рассматривается как источник переименования (обычно -M рассматривает только файл, который исчез как источник переименования), и число n управляет этим аспект опции -B (по умолчанию 50%) .
    -B20% указывает, что изменение с добавлением и удалением по сравнению с 20% или более размера файла может быть выбрано в качестве возможного источника переименования в другой файл.

-M[<n>]

При генерации различий обнаруживать и сообщать о переименованиях для каждого коммита. Следующие файлы в переименованиях при просмотре истории см. --follow.
Если указано n, это пороговое значение для индекса сходства (т. Е. Количество добавлений / удалений по сравнению с размером файла).
Например, -M90% означает, что git должен считать пару «удалить / добавить» переименованием, если более 90% файла не изменилось .


Дополнительные ссылки:


Примечание. В Git 2.18 (Q2 2018) git status теперь должно отображать переименования (вместо удаления / добавления файлов) при перемещении / переименовании файлов.
Смотрите " Как сказать Git, что это тот же каталог, просто другое имя ".

...