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

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

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


person Nicolas De loof    schedule 19.08.2010    source источник
comment
Подождите ... В этой книге Apache Maven, которая находится прямо передо мной, одно имя автора очень знакомо ...   -  person VonC    schedule 19.08.2010
comment
Я знал это! Я все еще пытаюсь забыть фотографию сумасшедшего Фреда из C'est pas sorcier, говорящего о миграции maven3 на недавнем JUG ... Хорошие времена;) Добро пожаловать на SO.   -  person VonC    schedule 19.08.2010


Ответы (1)


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

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

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

Однако это не означает, что Git не поддерживает переименований.
Механизм различий в Git поддерживает автоматическое обнаружение переименований, это включается переключателем '-M' на семейство команд git-diff-*.
< strong> Механизм обнаружения переименования используется 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 (второй квартал 2018 г.) git status теперь должен отображать переименование (вместо удаления / добавления файлов) при перемещении / переименовании файлов.
См. "Как сообщить Git, что это тот же каталог, только другое имя".

person VonC    schedule 19.08.2010
comment
Хорошо, но есть ли простой ответ на исходную ситуацию простым языком? Если я проведу рефакторинг класса Java, переместив его в другой каталог пакета, так что из (например) 100 строк была изменена одна строка, указывающая на пакет Java, журнал default и виноват распознают переместить / переименовать? Смогу ли я по-прежнему винить GitHub / BitBucket? Другими словами, будет ли все работать со стандартными настройками всего, если я выполню это (очень, очень, очень) обычное действие? - person Garret Wilson; 06.09.2015
comment
@GarretWilson да, это будет на локальной стороне (где вы можете вызвать git log --follow (как в stackoverflow.com/q/2314652/6309) или git blame -C. Это не будет выполняться на стороне сервера хостинга Git (GitHub: stackoverflow.com/a/5647721/ 6309) (или BitBucket: bitbucket.org/site/master/issues/589/) - person VonC; 06.09.2015
comment
Спасибо за быстрое разъяснение по ссылкам! Я воздержусь от комментариев к Git, которые, похоже, у меня нет другого выхода, кроме как использовать ... :) - person Garret Wilson; 06.09.2015