Как вычислить git-хеш-объект каталога?
У кого-нибудь есть пример использования git hash-object в каталоге? Он работает достаточно легко для файла *, но не работает, как я ожидал для каталога **
*: git hash-object c:\somefile.txt
**: git hash-object -t tree c:\somedirectory
Когда я пытаюсь использовать хеш-объект с каталогом, он жалуется: "Неустранимый: Невозможно открыть" C:\someDirectory ": Отказано в доступе"
6 ответов
git hash-object -t tree
ожидает, что параметром файла будет файл, который описывает записи в дереве, а не каталог в файловой системе. Из комментария я понимаю, что эта команда ожидает файл, описывающий дерево в двоичном формате, и что его будет проще использовать git mktree
для вас, чтобы создать объект дерева.
git mktree
понимает ввод формата, который вы получаете (например) git ls-tree HEAD
, Есть хороший пример построения дерева с нуля, используя git hash-object
а также git mktree
в Git Community Book.
В зависимости от того, почему вы хотите это сделать, может быть полезна следующая команда git:
git ls-files -s somedirectory | git hash-object --stdin
Это дает один хеш, который учитывает имена файлов и их содержимое.
Это работает так. git ls-files -s ....
выводит список файлов и их хэши в виде текста stdout
, затем git hash-object
генерирует хеш для данных, которые он получает от stdin
,
Мой пример использования для этого следующий: я хочу знать, точно ли (* управляемые) файлы в каталоге в одной ветви точно (*) совпадают с файлами в другой ветви. Конкретное использование заключается в сравнении "хэшей каталогов", чтобы решить, нужно ли мне повторно генерировать производные файлы, которые кэшируются.
По умолчанию git ls-files
будет перечислять файлы в подкаталогах тоже. Если вы не хотите этого, попробуйте поискать ответы на вопрос "как использовать git ls-file только для одного уровня каталогов". Существуют также различные другие варианты git ls-файлов, включая возможность указать список файлов для включения.
(*) исключая хеш-коллизии
Я не уверен в получении хеша для каталога вне репозитория git, но для каталога внутри репозитория попробуйте напечатать только хеш:
git rev-parse HEAD:some/directory
Нет необходимости использовать другие команды, требующие дополнительной обработки.
Это также будет работать, но предоставит дополнительную информацию, которая может вам не понадобиться (например, режим файла и другие данные):
git ls-tree HEAD some/directory
У меня была та же проблема, и я взломал скрипт Python для хэширования полного каталога. Он ограничен в том смысле, что не .gitignore
файл в учетную запись, но он до сих пор служит своей цели (хэш-каталог, сделать коммит-объект, сохранить его на gh-pages
филиал).
Я хотел бы улучшить ответ Fred Foo, предоставив модифицированную версию его скрипта, отличающуюся тем, что он не хранит файлы и каталоги в репозитории как побочный эффект вычисления их хэшей: http://pastebin.com/BSNGqsqC
К сожалению, я не знаю ни одного способа заставить git mktree
не создавать объект дерева в хранилище, поэтому код должен генерировать двоичное представление дерева и передавать его git hash-object -t tree
,
Этот скрипт также основан на ответах из Каков внутренний формат объекта дерева мерзавца?
Общая идея заключается в использовании git hash-object -- data.txt
получить хеш файла и использовать git hash-object --stdin -t tree < TreeDescription
для каталога, где:
- TreeDescription - это объединение
"mode name\0hash"
mode
является"100644"
для файлов и"40000"
для каталогов (обратите внимание на отсутствие начального нуля в случае каталога)mode
а такжеname
разделены одним пробелом,name
а такжеhash
разделены одним байтом\0
hash
является 20-байтовым длинным двоичным представлением объекта hash- записи отсортированы по
name
, который, как представляется, не совсем необходим для создания объекта дерева, но помогает определить, эквивалентны ли две директории, путем сравнения их хешей - к сожалению, я не знаю, какой алгоритм сортировки следует использовать здесь (в частности: что делать в случае отсутствия аськи персонажи)
Также обратите внимание, что этот двоичный формат немного отличается от способа хранения объекта дерева в хранилище тем, что в нем отсутствует "tree SIZE\0"
заголовок.
Очевидно, что вы должны вычислить это снизу вверх, начиная с самых глубоких файлов, так как вам нужно хешировать все дочерние элементы перед вычислением хеша родительского элемента.
После долгих поисков я нашел следующую команду:
git write-tree
Источник: http://git-scm.com/docs/git-write-tree
Я использовал его, чтобы восстановить отсутствующий каталог:
git write-tree path/to/missing/folder
И мой отсутствующий объект дерева был создан. Отсюда вы можете продолжить использовать:
git hash-object -w path/to/missing/folder/file.txt
Как объяснено в: https://git.wiki.kernel.org/index.php/GitFaq
Как сказал Марк Лонгэйр, mktree - это путь.
У меня была та же проблема, и мне пришлось много бороться, чтобы ее исправить. Вот что я сделал:
git ls-files -s directory_path
Это даст вам список содержимого каталога с его хешами.
Затем вы можете превратить этот список в формат ls-tree в текстовом редакторе и
echo -e "{ls-tree format list}" | git mkdir