Как Git отслеживать историю во время рефакторинга?

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

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

Ответ 1

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

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

Во второй заметке отслеживание переименований на самом деле является просто особым случаем отслеживания перемещения контента в дереве. В некоторых случаях вы можете быть заинтересованы в запросе, когда функция была добавлена ​​или перенесена в другой файл. Основываясь только на возможности воссоздать эту информацию по мере необходимости, 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>]

Перерыв завершите переписывание изменений в пары delete и create. Это служит двум целям:

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

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

-M[<n>]

Если вы создаете diff, обнаруживаете и сообщаете переименования для каждой фиксации. Для следующих файлов переименований во время прохождения истории см. --follow.
Если указано n, это значение является пороговым значением индекса подобия (т.е. количества добавлений/исключений по сравнению с размером файла).
Например, -M90% означает, что Git должен рассматривать пару delete/add как переименование, если более 90% файла не изменилось.


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