Кажется, я нашел для этого причину. Фиксация f56f31af0301
на Git изменила реализацию sparse-checkout
, так что, когда у вас есть неинициализированное рабочее дерево (как если бы вы сразу после запуска git clone --no-checkout
), запуск git sparse-checkout init
не проверял из любых файлов в ваше рабочее дерево. В предыдущих версиях команда фактически извлекала файлы, что могло иметь неожиданные последствия, учитывая, что в этот момент у вас не было активной ветки.
Соответствующий коммит, f56f31af0301
был включен в Git 2.27, но не в 2.25. Это объясняет, почему поведение, которое вы видите, не соответствует поведению, показанному на веб-странице, за которой вы пытаетесь следовать. По сути, поведение на веб-странице было ошибкой, которую в то время никто не осознавал, но в Git 2.27 она была исправлена.
Это очень хорошо объяснено, я думаю, в сообщение для фиксации b5bfc08a972d
:
Итак ... это подводит нас к особому случаю: клон git, выполненный с --no-checkout
. Согласно значению флага, --no-checkout
не проверяет какую-либо ветку, что подразумевает, что вы не в одной из них и вам нужно переключиться на одну после клона. Реализационно HEAD
все еще установлен (так что в некотором смысле вы частично находитесь в ветке), но
- индекс «нерожденный» (не существует)
- есть в рабочем дереве нет файлов (кроме
.git/
) - при следующем запуске
git switch
(или git checkout
) он запустит unpack_trees с флагом initial_checkout
, установленным в значение true.
Только когда вы запустите, например git switch <somebranch>
, индекс будет записан, а файлы в рабочем дереве заполнены.
В этом особом случае --no-checkout
традиционное поведение read-tree -mu HEAD
сделал бы эквивалент действия checkout
- переключитесь на ветвь по умолчанию (HEAD
), выпишите индекс, соответствующий HEAD
, и обновите рабочее дерево для соответствия. Этот особый случай проскользнул через проверки на предотвращение внесения изменений в исходной команде sparse-checkout
и, таким образом, продолжился там.
После того, как update_sparsity()
был введен и использован (см. Коммит f56f31a
("sparse-checkout: use new update_sparsity() function
", 2020-03-27)), поведение для случая --no-checkout
изменилось: из-за автоматического оживления git пустого индекса в памяти (см. do_read_index()
и обратите внимание, что must_exist
является ложным), и из-за кода sparse-checkout
update_working_directory()
всегда записывать индекс после того, как это было сделано, мы получили новую ошибку. Это сделало так, что sparse-checkout
переключит репозиторий с клона с «нерожденным» индексом (т.е. все еще нуждающимся в initial_checkout
) на тот, у которого есть записанный индекс без записей. Таким образом, вместо того, чтобы все файлы, появляющиеся в git status
, были известны git как особый артефакт того, что они еще не находятся в ветке, наша запись пустого индекса заставила его внезапно обратиться к git, как если бы он определенно был на ветке со ВСЕМИ файлами, поставленными на удаление! Последующая проверка или переключение должны были иметь дело с тем фактом, что он не был на initial_checkout
, но имел кучу поэтапных удалений.