Ваше внутреннее описание в основном верно. Единственное, что не на 100% связано с этой частью:
Каждый раз при постановке изменений с git add
объект blob создается в .git / objects /
Внутренне git add
хеширует содержимое данных в файле рабочего дерева, как git hash-object -w -t blob
. Это не обязательно создает новый объект: если хешированное содержимое уже находится в репозитории, он просто повторно использует существующий объект. Существующий объект может быть упакован, т. Е. В .git/objects/pack
, а не свободно как отдельный большой двоичный объект.
Более того, содержимое, записанное в объект blob, может произвольно отличаться от содержимого в дереве работы из-за чистого фильтра. Чаще всего CR-LF-line-end-отличается от содержимого в рабочем дереве из-за настроек окончания строки. Чистые фильтры и настройки конца строки частично (или в основном, в зависимости от того, как вы используете Git) контролируются через ваш .gitattributes
файл и частично (или в основном) через настройки в вашей конфигурации.
В любом случае важно то, что вы получаете идентификатор хэша для объекта blob. Объект blob определенно существует где-то - в каталоге .git/objects
как свободный объект или в файле пакета. Теперь git add
может записывать в .git/index
(или в любой другой файл, указанный GIT_INDEX_FILE
): он сохранит в индексе в нулевом промежуточном слоте запись для данного path
, используя вычисленный хеш-код blob и режим 100644
или 100755
в зависимости от того, следует ли позже пометить файл рабочего дерева как исполняемый.
Если вы его потеряли, вам больше не повезло
[Сценарий вырезан, но он заканчивается git checkout HEAD -- path
затиранием записи индекса, где его $path
представляет $blobhash
и информацию о режиме $mode
, и затирание копии рабочего дерева файла в < em> path
.)
Если только сборка мусора не сработает, технически контент все еще существует. Но я не знаю, как бы мне его вернуть, кроме как вручную попытаться каким-то образом найти хеш и прочитать содержимое с помощью git cat-file
.
В самом деле, вы не можете: вычисление хеш-идентификатора - это функция лазейки, и только если вы иметь хэш, может у вас Git выплеснет контент, но у вас должен быть контент, если у вас нет хеша. Это ваша ситуация Catch-22.
Если - это очень важное «если» - контент был уникальным, так что git add
действительно создал новый объект blob, и вы только что перезаписали ссылку на большой двоичный объект, которая была в индексе, этот объект большого двоичного объекта действительно больше нигде не ссылается. С другой стороны, если git hash-object -w
пришлось повторно использовать какой-либо существующий большой двоичный объект, на объект большого двоичного объекта по-прежнему ссылается то, на что ссылалось ранее. Итак, теперь есть два интересных случая: большой двоичный объект был уникальным и теперь подходит для сборки мусора, или большой двоичный объект был не уникальным и не является.
Используя git fsck --lost-found
, git fsck --unreachable
или git fsck --dangling
(по умолчанию), вы можете заставить Git пройти всю базу данных объектов, определить, какие объекты достижимы, а какие нет, и рассказать вам о некоторых или всех недостижимых и / или скопировать информацию из них или о них в .git/lost-found
. Если объект BLOB-объекта был недоступен, он будет указан как один из этих недоступных или зависших BLOB-объектов или его содержимое будет восстановлено в .git/lost-found
.
Недостатком здесь является то, что могут быть десятки или даже сотни висящих объектов-капель. Теперь ваша задача переключилась с «угадать решетку» (практически невозможно) на «найти иголку в стоге сена» (не так сложно, но утомительно, и вы вполне можете найти неправильную иголку - это не так действительно стог сена, все-таки стопка иголок). И, конечно же, это работает только для случая, когда blob был уникальным.
Ответы на конкретные вопросы
(Кстати, именно здесь этот вопрос не на самом деле дубликат Может git отменить оформление заказа неустановленных файлов. Но он по-прежнему полезен, так что посмотрите его тоже.)
Есть ли что-то вроде git reflog
для индекса?
Нет. Вы можете делать свои собственные резервные копии: просто cp .git/index
где-нибудь. Но Git не делает этого сам по себе. Вы можете создать его непосредственно перед git checkout HEAD -- path
операцией, используя псевдоним или функцию оболочки, которую вы используете для выполнения этой опасной операции.
Обратите внимание, что Git не знает об этих резервных копиях, поэтому git gc
не будет считать объекты, на которые есть ссылки, защищенными. Чтобы использовать резервные копии с такими командами сантехники, как git ls-files
, поместите имя пути в GIT_INDEX_FILE
на время действия этой команды.
Считается ли git checkout @ --
файл опасной командой, например git reset --hard
, где вы потенциально можете потерять свою работу?
Ответ на этот вопрос зависит от того, кто думает. Я бы порекомендовал считать это опасным, раз уж вы вообще задаете вопрос. :-)
Есть ли сантехнические команды для ручного изменения / перезаписи индекса? (см. вышеупомянутый случай, когда объекты все еще находятся на месте)
Да: git update-index
- средство обновления с однократной записью (используйте --cacheinfo
или --stdin
, чтобы предоставить необработанные данные о записях индекса, а не дублировать много git add
работы). Многие другие команды также частично или массово обновляют индекс.
Если у вас есть процесс резервного копирования индекса перед операцией git checkout HEAD -- ...
, вы можете считывать записи из резервного индекса (например, используя GIT_INDEX_FILE=... git ls-files
), а затем использовать git update-index
, без установки GIT_INDEX_FILE
, поместить информацию в обычный указатель. Конечно, поскольку это операция перезаписи индекса, вы можете сначала сделать еще одну резервную копию индекса.
Есть ли альтернативный способ извлечения одного файла без его мгновенной постановки?
Нет, но только из-за глагола checkout. Чтобы просмотреть содержимое файла, который находится либо в индексе, либо в любом коммите, чтобы содержимое имело имя, понятное git rev-parse
, используйте git show
:
git show :file # file in index at stage zero
git show :3:file # file in index at stage three, during merge conflict
git show HEAD:file # file in current commit
git show master~7:file # file in commit 7 first-parent hops back from master
Также обратите внимание, что git reset
может перезаписать один или несколько файлов в индексе, не касаясь файлов в рабочем дереве:
git reset HEAD -- file # copy HEAD:file to :file leaving work-tree file undisturbed
Если вы укажете git reset
путь к каталогу, он сбрасывает все файлы, которые уже находятся в индексе и находятся в этом каталоге.
person
torek
schedule
09.03.2019