Ваше описание под капюшоном в основном верно.Единственные вещи, которые не на 100% связаны с этой частью:
Каждый раз, когда этап изменяется с git add
, объект BLOB создается в .git / objects / * 1006.*
Внутренне, git add
хэширует содержимое данных в файле рабочего дерева, как git hash-object -w -t blob
.Это не обязательно создает новый объект: если хешированное содержимое уже в хранилище , оно просто повторно использует существующий объект.Существующий объект может быть упакован , т. Е. В .git/objects/pack
, а не Свободный в качестве отдельного большого двоичного объекта.
Кроме того, содержимое записывается в объект большого двоичного объекта может быть произвольно отличным от содержимого в рабочем дереве из-за чистого фильтра .Чаще всего CR-LF-конец строки отличается от содержимого в рабочем дереве из-за настроек окончания строки.Чистые фильтры и настройки конца строки контролируются частично (или в основном, в зависимости от того, как вы используете Git) через ваш файл .gitattributes
, и частично (или в основном) через настройки в вашей конфигурации.
В любомДело в том, что вы получаете хеш-идентификатор для объекта BLOB-объекта.Объект BLOB-объектов определенно существует где-то - в каталоге .git/objects
как свободный объект или в файле пакета.Теперь git add
может записывать в .git/index
(или любой другой файл, который указывает GIT_INDEX_FILE
): он будет хранить в индексе на нулевом временном интервале запись для данного path
, используяВычисляем blob-хэш и режим 100644
или 100755
в зависимости от того, должен ли файл рабочего дерева быть помечен как исполняемый позже.
Если вы его потеряли, вам в основном не повезло
[Сценарий пропущен, но он заканчивается git checkout HEAD -- <em>path</em>
, перекрывающим запись индекса, с $path
, представляющим $blobhash
и режимом $mode
информация, и , перекрывающимкопия файла рабочего дерева в path
.)
Если технически все еще нет места для сбора мусора в контенте.Но я не знаю, как бы получить его обратно, кроме ручной попытки как-то найти хеш и чтения содержимого с помощью git cat-file
.
Действительно, вы не можете: вычисление хеш-идентификатораэто функция trapdoor , и только если у вас do есть хеш, вы можете заставить Git выдавать контент, но вам нужно иметь контент, если у вас нет хеша.Это ваша ситуация Catch-22 .
Если - это довольно важное «если» - контент был уникальным, так что git add
действительно создал новый объект BLOB, и , вы только что переписали ссылку BLOB-объекта, которая была в индексе, на этот объект BLOB действительно больше нигде не ссылаются.С другой стороны, если git hash-object -w
повторно использует существующий BLOB-объект, объект BLOB-объекта все еще ссылается на то, на что он ссылался ранее.Итак, теперь есть два интересных случая: BLOB-объект был уникальным и теперь пригоден для сбора мусора, или BLOB-объект не уникален и не является.
Использованиеgit fsck --lost-found
или git fsck --unreachable
или git fsck --dangling
(по умолчанию), вы можете заставить Git обходить всю базу данных объектов, определять, какие объекты достижимы , а какие нет, и сообщать вам о некоторых или всехнедоступные и / или скопировать информацию из или о них в .git/lost-found
.Если объект BLOB был недоступен, он будет включен в список как один из этих недоступных или висячих объектов или его содержимое будет восстановлено в .git/lost-found
.
Недостатокздесь могут быть десятки или даже сотни объектов с висящими каплями.Ваша задача теперь переключилась с «угадать хеш» (практически невозможно) на «найти иголку в стоге сена» (не так сложно, но утомительно, и вы вполне могли бы найти неправильную иглу - это не совсем такстог сена, это в конце концов стека игл).И, конечно же, это работает только для случая "blob был уникальным".
Ответы на конкретные вопросы
(Tон, кстати, где этот вопрос не действительно дубликат Может git отменить извлечение неподготовленных файлов .Но этот по-прежнему полезен, так что посмотрите и его.)
Есть ли что-то вроде git reflog
для индекса?
Нет.Вы можете создавать свои собственные резервные копии: просто cp .git/index
где-нибудь.Но Git не делает это самостоятельно.Вы можете сделать его непосредственно перед операцией git checkout HEAD -- <em>path</em>
, используя псевдоним или функцию оболочки, которую вы используете для выполнения этой опасной операции.
Обратите внимание, что 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
, чтобы поместить информацию в обычный индекс.Конечно, это операция перезаписи индекса y, вы можете сначала сделать еще одну резервную копию индекса.
Есть ли альтернативный способ извлечения отдельного файла без мгновенной его постановки?
Нет, но только из-за глагола 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
путь к каталогу, онсбрасывает все файлы, которые уже есть в индексе и находятся в каталоге.