Как Git отражает изменения из своих объектов в файловой системе? - PullRequest
0 голосов
/ 28 августа 2018

Я просмотрел книгу Git Internals и в основном понимаю, как Git структурирует вещи в BLOB-объекты, деревья, коммиты и что ветви - это легкие указатели на коммиты.

Часть, которую я не совсем понимаю, это то, как Git отображает эти изменения в файловой системе через проверки ветвления / фиксации.

Например:

Рассмотрим два файла, A.txt и B.txt, зафиксированных в Commit 1. В дополнение к двум файлам файл C.txt фиксируется в Commit 2.

Из того, что я понимаю, граф объектов будет выглядеть следующим образом:

  1. Commit 1 указывает на Tree 1, в котором есть двоичные объекты для двух исходных файлов - BlobA и BlobB
  2. Commit 2 указывает на Tree 2, в котором есть капли для трех файлов. BlobA и BlobB остаются прежними, поскольку их содержимое не изменилось, в то время как BlobC также будет ниже Tree 2.

Теперь, если я в данный момент на Commit 2 и проверяю на Commit 1, HEAD теперь указывает на Commit 1, и мы можем пройти ориентированный граф, который сообщает состояние хранилища. Теперь файл C.txt больше не находится в файловой системе.

Как Git отражает состояние графа объектов в файловой системе при каждой проверке?

Спасибо.

1 Ответ

0 голосов
/ 28 августа 2018

Большинство действий дерева 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 действительно должен - но не делает - различать «игнорировать этот файл, потому что его легко создать заново», и «игнорировать этот файл, потому что он не должен быть зафиксирован, но никогда не сжимает его , потому что он содержит что-то драгоценное, например данные конфигурации пользователя. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...