Краткая версия:
меньше, чем исходный код
git
, где я могу найти полное описание эвристик, которыеgit
использует для связывания фрагментов контента с определенными отслеживаемыми дорожками?
Подробная версия:
В демонстрационном взаимодействии оболочки Unix) ниже, два файла a
и b
: "git-commit
'ted", затем они изменяются так, чтобы (эффективно) передавать большую часть контента a
до b
, и, наконец, два файла снова совершаются.
Ключевое значение, которое нужно искать, состоит в том, что вывод второго git commit
заканчивается строкой
rename a => b (99%)
, даже если не было переименования файлов (в обычном смысле) (!?!).
Прежде чем показывать демонстрацию, это краткое описание упростит работу.
Содержимое файлов a
и b
генерируется путем объединения содержимого трех вспомогательных файлов ../A
, ../B
и ../C
. Символьно, что состояния a
и b
могут быть представлены как
../A + ../C -> a
../B -> b
перед первым фиксацией и
../A -> a
../B + ../C -> b
прямо перед вторым.
ОК, здесь демо.
Сначала мы показываем содержимое вспомогательных файлов ../A
, ../B
и ../C
:
head ../A ../B ../C
# ==> ../A <==
# ...
#
# ==> ../B <==
# ###
#
# ==> ../C <==
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
(Строки, начинающиеся с #
соответствуют выходу на терминал, фактические выходные линии не имеют ведущего #
.)
Затем мы создаем файлы a
и b
, отображаем их содержимое и фиксируем их
cat ../A ../C > a
cat ../B > b
head a b
# ==> a <==
# ...
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
#
# ==> b <==
# ###
git add a b
git commit --allow-empty-message -m ''
# [master (root-commit) 3576df7]
# 2 files changed, 8 insertions(+)
# create mode 100644 a
# create mode 100644 b
Затем мы изменяем файлы a
и b
и отображаем их новое содержимое:
cat ../A > a
cat ../B ../C > b
head a b
# ==> a <==
# ...
#
# ==> b <==
# ###
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
Наконец, мы фиксируем измененные a
и b
; обратите внимание на вывод git commit
:
git add a b
git commit --allow-empty-message -m ''
# [master 25b806f]
# 2 files changed, 2 insertions(+), 8 deletions(-)
# rewrite a (99%)
# rename a => b (99%)
Я рационализирую это поведение следующим образом.
Как я понимаю, git
рассматривает информацию о структуре каталогов (например, имена файлов отслеживаемых файлов) в качестве дополнительной информации или метаданных, если вы хотите, чтобы быть связанными с основной информацией, которую она отслеживает, а именно различными куски контента.
Поскольку как содержимое, так и имена (в том числе пути) файлов могут меняться между коммитами, git
должен использовать эвристику для связывания имен путей с кусками содержимого. Но эвристика по самой своей природе не гарантируется в 100% случаев. Провал такой эвристики здесь имеет форму истории, которая точно не отражает то, что на самом деле произошло (например, оно сообщает о переименовании файла, даже если файл не был переименован в обычном смысле).
Следующее подтверждение этой интерпретации (а именно, что некоторые эвристики находятся в игре) заключается в том, что AFAICT, если размер переданного фрагмента недостаточно велик, вывод git commit
не будет включать строки rewrite/rename
, (Я включаю демонстрацию этого случая в конце этого сообщения, FWIW.)
Мой вопрос заключается в следующем: не хватает исходного кода
git
, где я могу найти полное описание эвристик, которыеgit
использует для связывания фрагментов контента с определенными отслеживаемыми дорожками?
Эта вторая демонстрация идентична первой во всех отношениях, за исключением того, что вспомогательный файл ../C
- это одна строка короче, чем раньше.
head ../A ../B ../C
# ==> ../A <==
# ...
#
# ==> ../B <==
# ###
#
# ==> ../C <==
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
cat ../A ../C > a
cat ../B > b
head a b
# ==> a <==
# ...
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
#
# ==> b <==
# ###
git add .
git commit -a --allow-empty-message -m ''
# [master (root-commit) a06a689]
# 2 files changed, 7 insertions(+)
# create mode 100644 a
# create mode 100644 b
cat ../A > a
cat ../B ../C > b
head a b
# ==> a <==
# ...
#
# ==> b <==
# ###
# =================================================================
# =================================================================
# =================================================================
# =================================================================
# =================================================================
git add .
git commit -a --allow-empty-message -m ''
# [master 87415a1]
# 2 files changed, 5 insertions(+), 5 deletions(-)