Большинство действий дерева Git фактически контролируются с помощью index . Это означает, что обход графа вообще не требуется!
Основная роль индекса (по крайней мере, вне слияний) состоит в том, чтобы выступать в качестве места, в котором вы создаете следующий коммит. Это дает ему имя, которое многие люди предпочитают использовать, область подготовки . В индексе версия файла, такая как README.txt
, начнет совпадать с версией HEAD
того же файла. Оба файла фактически хранятся в хранилище как объект blob .
Рабочее дерево будет содержать пригодную для использования версию README.txt
, представляющую расширенную версию файла. Это также фильтруется по пятнам и CRLF, если вы установили такую фильтрацию. Если вы изменяете версию рабочего дерева и хотите зафиксировать изменения, вы должны запустить git add README.txt
: это скопирует файл рабочего дерева обратно в индекс, применяя любой чистый фильтр и выполняя корректировку CRLF-to-LF, если вы включите их, создав новый большой двоичный объект в хранилище (или повторно используя существующий большой двоичный объект, если содержимое нового файла соответствует некоторому существующему содержимому), и сохраните новый хэш в индексе. По сути, это заменяет индексную копию файла.
Пока все хорошо, но что произойдет, если у вас получен какой-нибудь коммит, например, в результате git checkout master
, и вы введете команду git checkout develop
? Здесь индекс берет на себя вторую роль, которая заключается в том, чтобы отслеживать, т. Е. Индекс, рабочее дерево и хранить в кэше информацию о рабочем дереве. (Это также источник его третьего имени, кеш .)
Git уже перевел master
в хеш коммита для извлечения этого коммита, но на этом этапе он делает это снова. На данный момент Git использует так называемый режим слияние двух деревьев команды git read-tree
. Он также переводит develop
в хеш коммита, поэтому теперь у него есть два хэша коммитов, для master
(текущий коммит) и develop
(требуемый коммит). Убедившись, что это действительно коммиты, 1 Git преобразует их в хеш-идентификаторы дерева: дерево HEAD
и желаемое или целевое дерево.
Между тем в index указывается хэш-идентификатор для каждого отслеживаемого файла в рабочем дереве. В идеальном случае для каждого файла F в индексе и / или в HEAD
коммите F будет иметь одинаковый хэш как в HEAD
, так и в индексе. Если это так, индексная копия F
сама по себе «чистая» (соответствует). Копия рабочего дерева может быть или не быть чистой (может совпадать или не совпадать с копией индекса) - роль индекса как кеш здесь помогает сделать этот последний тест очень быстрым в большинстве случаев.
Для каждого файла F , существующего в и HEAD
и целевом дереве, либо целевой хеш для F совпадений хэш HEAD
для F
или нет. Для файлов, которые не существуют в целевом дереве, но существуют в HEAD
, либо индекс и копия рабочего дерева F чистые, либо их нет. Если файл чистый, то можно удалить обе копии (если файл отсутствует в целевой папке) или заменить обе версии версией из целевого дерева (если файл находится в целевой папке). Но если хеш целевого дерева совпадает с хешем HEAD
, нет необходимости вообще касаться индекса и записи рабочего дерева, поэтому Git этого не делает.
Короче говоря, только там, где HEAD
и целевые деревья не не соответствуют, Git должен что-то изменить в рабочем дереве, чтобы получить извлечение. Если часть, которая не соответствует, является файлом xyz.txt
в HEAD
, но не в цели, целью становится удалить xyz.txt
- но это разрешено только в том случае, если он «чистый», если, конечно, вы не добавите --force
к вашему git checkout
. Если часть, которая не соответствует, состоит в том, что файл не находится ни в HEAD
, ни в индексе, но равен в цели, цель становится create xyz.txt
с целью содержимое - но это допустимо только в том случае, если файл не существует или если файл указан в директиве игнорирования. 2
1 Имена ветвей требуются для постоянной идентификации хешей. (Имена тегов разрешены для идентификации других типов объектов.) Таким образом, в теории нет необходимости проверять это. Действительно ли Git проверяет, зависит от пути к коду.
2 Эта последняя часть порой вызывает серьезную боль. Git действительно должен - но не делает - различать «игнорировать этот файл, потому что его легко создать заново», и «игнорировать этот файл, потому что он не должен быть зафиксирован, но никогда не сжимает его , потому что он содержит что-то драгоценное, например данные конфигурации пользователя. "