Почему Git ведет себя так? Несоответствие между ОС и ВМ, обращающимися к одному и тому же хранилищу - PullRequest
0 голосов
/ 24 августа 2018

Позвольте мне объяснить настройки .. У меня есть компьютер (Windows, не уверен, является ли это переменная здесь или нет), который имеет git-репозиторий.Это хранилище работает и ведет себя, как и ожидалось, ради этого вопроса предположим, что один файл был обновлен и еще не зафиксирован в текущей ветви.У меня также есть VM (Linux) на коробке.Виртуальная машина может получить доступ к файловой системе через общий ресурс и смонтированный диск обратно в хост-систему.На виртуальной машине установлен git и аутентифицирован репозиторий git.

На виртуальной машине я вижу текущую ветку из команды git branch.Однако, если я запрашиваю список незафиксированных файлов через git status или git add --dry-run ., я получаю список каждого файла, а не единственный незафиксированный файл, который я ожидаю увидеть.Еще одна подсказка, которую я обнаружил, заключается в том, что если я буду выполнять длительный процесс, скажем git add --dry-run ., пока этот процесс пойдет в гору, если я должен был выполнить ту же команду в операционной системе хоста, я получу ошибку о файле блокировки git (который говорит мнечто они используют одну и ту же файловую систему / базу данных).Я предположил, что это может быть вызвано тем, что файловая система NTFS хоста нечувствительна к регистру, а гостевая файловая система EXT4 чувствительна к регистру, но я вижу, что регистры файлов совпадают и сообщаются git одинаково.

Итак, вопрос в том, почему гостевая ОС показывает зафиксированные файлы как неподтвержденные?

Может быть связано с Как внутреннее состояние git работает?

1 Ответ

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

Git на самом деле не имеет понятия «незафиксированный файл».У него есть index и work-tree .

. Главное, что хранит Git: commits:

  • Коммиты - это постоянные (в основном 1 ), полностью доступные только для чтения сущности, хранящиеся в своего рода базе данных (простое хранилище значений ключей , действительно), которыеразрешить Git получить доступ к полному снимку источника, который вы или коммиттер сделали, когда вы или коммиттер сделали этот коммит.Наряду с этим моментальным снимком, вы - я не буду здесь указывать «или коммиттер», но, конечно, это подразумевается, - получите возможность добавить свои собственные метаданные, в частности, сообщение журнала о почему Вы сделали этот коммит.

    «Истинное имя» любого коммита - это его хэш-идентификатор.Git использует хэш-идентификатор в качестве ключа в хранилище значений ключей, чтобы получить фиксацию.Каждый коммит также содержит хеш-идентификатор своего предшественника или родительский коммит (или, для коммитов слияния, два или более родительских хеш-идентификатора - это то, что делает их «коммитами слияния»).

Один коммит всегда является текущим коммитом.Это тот коммит, который вы выбрали (через git checkout) для работы.Поскольку коммиты доступны только для чтения, вы не можете изменить этот коммит.В какой-то момент вы можете сделать новый коммит.Обычно этот новый коммит будет использовать текущий коммит в качестве родителя нового коммита, а затем станет текущим коммитом, и именно поэтому вы всегда можете вернуть каждый файл, который вы когда-либо фиксировали: коммиты являются постоянными (в основном)и только для чтения (полностью) и помните своих родителей.

Файлы, сохраненные с коммитом - сделанным вами снимком - сохраняются в сжатом формате Git-only, который бесполезен ни для чего, кроме Git.Таким образом, эти файлы должны быть извлечены из каждого коммита, прежде чем вы сможете их использовать.Следовательно, Git также имеет:

  • Рабочее дерево.Здесь Git может извлечь файлы из коммита в формат, в котором их использует компьютер.Эти файлы не должны передаваться между компьютерами не потому, что он не может работать, а потому, что он может, и это просто создает большие головные боли, как вы обнаруживаете.

    Поскольку файлы в работе -дерево хранится в собственном формате и используется другими программами. Git предлагает возможность модифицировать файлов - особенно таких, как окончания строк и биты разрешений, - когда они выходят из коммита в пути.в рабочем дереве, и когда они переходят из рабочего дерева в коммит.Но есть еще один ключевой момент, и именно здесь возникают самые большие головные боли.

  • index .Этот элемент находится между текущего коммита и рабочим деревом.

Индекс хранит все файлы в специальном формате Git-only.Это начинается , содержащее файлы, какими они были, когда они были зафиксированы.Ключевое различие между копией файлов коммита и копией индекса заключается в том, что вы можете изменить тех, что в индексе.Вы изменяете их на , заменяя их оптом , используя git add, чтобы скопировать файл рабочего дерева обратно в индекс.

Когда вы делаете новый коммит, Gitпросто использует то, что находится в индексе в то время.Все файлы уже есть, все предварительно упакованы в формате Git-only.Это делает фиксацию очень быстрой.

Это также означает, что преобразование из формата Git-only в формат «может использоваться этим компьютером» и наоборот происходит при копировании из индекса в рабочийtree (который изменяет файлы с Git-only на useable) и git add копировать из рабочего дерева в индекс (который меняет useable на Git-only).

Этопочти всегда самая медленная часть работы с коммитами и файлами, поэтому индекс отслеживает (индексы!) рабочего дерева, используя информацию, специфичную для ОС.Эта специфичная для ОС информация, найденная через ОС о рабочем дереве, попадает в индекс.

Если вы разделяете рабочее дерево и файлы индекса и .git на разных машинах,происходит то, что сам индекс становится бесполезным, потому что специфичные для ОС данные рабочего дерева хранятся в , индекс предназначен для ВМ или хоста, но никогда для обоих одновременно.

Если индекс верен и правильно описывает рабочее дерево, git status быстро и точно.Когда это не так, два различий, которые он должен выполнить - см. Мой ответ на вопрос, который вы связали - не могут быть выполнены почти так же эффективно.Если вы используете какие-либо преобразования файлов, их нужно либо повторно запустить, либо предположить, что они изменили файлы.

TL; DR всего этого: Никогда не делиться Gitтаким образом, используйте хранилище для извлечения данных. Это не потому, что он не работает, а потому, что он может работать, но становится ужасным опытом.Выявленные вами проблемы сворачивания имен файлов - это вершина другого целого кошмарного айсберга (не решается напрямую, если не делится хранилищем, но, по крайней мере, возможно , чтобы решить эту проблему).

1 Вы можете удалить коммит, если вы также удалите всех его детей и их детей и так далее.То есть удаление коммита требует своего рода геноцида на линии коммита.Это часто плохая идея, и если вы собираетесь это делать, вам обычно приходится копировать всю цепочку детей, но иногда это хорошая идея, и фактически это то, что git rebase делает внутри.

Обратите внимание, что git commit --amend не не меняет коммит.Вместо этого он просто отодвигает (и, таким образом, в конечном итоге убивает и удаляет) существующий коммит в конце цепочки, создавая новый замещающий коммит в конце цепочки, используя в качестве родителя нового коммита родительский элемент текущего коммита.

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