Может ли Git действительно отслеживать перемещение одной функции из одного файла в другой? Если да, то как?
Несколько раз я сталкивался с утверждением, что если вы перемещаете одну функцию из одного файла в другой файл, Git может отслеживать ее. Например, эта запись говорит: "Линус говорит, что если вы переместите функцию из одного файла в другой, Git сообщит вам историю этой единственной функции через двигаться".
Но у меня есть немного понимания некоторых из Git дизайна под капотом, и я не вижу, как это возможно. Так что мне интересно... это правильное утверждение? И если да, то как это возможно?
Мое понимание заключается в том, что Git хранит каждое содержимое файла как Blob, и каждый Blob имеет уникальную глобальную идентификацию, которая возникает из хэша SHA его содержимого и размера. Git затем представляет папки как деревья. Любая информация о имени файла принадлежит дереву, а не к Blob, поэтому переименование файла, например, отображается как изменение дерева, а не в Blob.
Итак, если у меня есть файл с именем "foo" с 20 функциями в нем и файл под названием "bar" с 5 функциями в нем, и я перехожу одну из функций из foo в bar (в результате получается 19 и 6, соответственно), как Git обнаружить, что я переместил эту функцию из одного файла в другой?
По моему мнению, это приведет к появлению 2 новых blobs (один для измененного foo и один для модифицированного бара). Я понимаю, что diff можно рассчитать, чтобы показать, что функция была перенесена из одного файла в другой. Но я не вижу, как история о функции может стать ассоциированной с баром, а не foo (не автоматически, во всяком случае).
Если Git должен был заглянуть внутрь отдельных файлов и вычислить blob для каждой функции (что было бы сумасшедшим/неосуществимым, потому что вам нужно было бы знать, как разбирать любой возможный язык), тогда я мог видеть, как это возможно.
Итак... утверждение правильное или нет? И если это правильно, то чего не хватает в моем понимании?
Ответы
Ответ 1
Эта функция предоставляется через git вину -C
Опция -C устанавливает git в попытку найти совпадения между добавлением или удалением фрагментов текста в просматриваемом файле и файлы, измененные в тех же наборах изменений. Дополнительно -CC или -CCC расширяют поиск. Введите git справку об ошибке на странице руководства.
Попробуйте себя в тестовом репо с git вином -C, и вы увидите, что блок кода, который вы только что переместили, возник в исходном файле, где он принадлежал.
Ответ 2
Немного эта функциональность находится в git gui blame
(+ имя файла). Он показывает аннотацию строк файла, каждый из которых указывает, когда он был создан и когда последний изменен. Для перемещения кода по файлу он показывает фиксацию исходного файла в качестве создания и фиксацию, где он был добавлен в текущий файл как последнее изменение. Попробуйте.
То, что я действительно хотел бы, это дать git log
, как некоторый аргумент, номер строки диапазона дополнительно к пути к файлу, а затем он покажет историю этого кодового блока. Такой вариант отсутствует, если документация правильная. Да, из заявления Линуса я тоже думаю, что такая команда должна быть легко доступна.
Ответ 3
От Git 2.15, git diff
теперь поддерживает обнаружение перемещенных строк с опцией --color-moved
. Он работает для перемещения по файлам.
Он работает, очевидно, для цветного вывода терминала. Насколько я могу судить, нет возможности указывать ходы в формате обычного текстового патча, но это имеет смысл.
Для поведения по умолчанию попробуйте
git diff --color-moved
Команда также принимает опции, которые в настоящее время являются no
, default
, plain
, zebra
и dimmed_zebra
(используйте git help diff
для получения последних опций и их описаний). Например:
git diff --color-moved=zebra
В отношении того, как это делается, вы можете получить некоторое понимание от этот обмен электронной почтой автором функциональности.
Ответ 4
git вообще не отслеживает переименования. Переименование - это просто удалить и добавить, что все. Любые инструменты, которые показывают переименования, восстанавливают их из этой истории.
Таким образом, функции переименования функций отслеживания - это простой вопрос анализа различий всех файлов в каждой фиксации после факта. В этом нет ничего невозможного; существующее отслеживание переименования уже обрабатывает "нечеткие" переименования, в которых некоторые изменения выполняются в файле, а также переименовываются; это требует просмотра содержимого файлов. Это было бы простое расширение для поиска переименований функций.
Я не знаю, действительно ли базовые инструменты git делают это, но они стараются быть нейтральными по отношению к языку, а идентификация функций очень не является нейтральной для языка.
Ответ 5
Там git diff
, который покажет вам, что некоторые строки исчезли из foo
и снова появились в bar
. Если в этих файлах нет других изменений в этих файлах, это изменение будет легко распознано.
Интеллектуальный клиент git
сможет показать вам, как строки перемещаются из одного файла в другой. Языковая среда IDE сможет соответствовать этому изменению с помощью определенной функции.
Очень похоже на то, что файл переименовывается. Он просто исчезает под одним именем и появляется под другим, но любой разумный инструмент может заметить его и представлять как переименование.