Как вычислить 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
Другие вопросы по тегам