git cat-file - інструмент для читання будь-якого об'єкта з бази:
git cat-file -t a1b2c3d # тип: blob, tree, commit, tag
git cat-file -s a1b2c3d # розмір у байтах
git cat-file -p a1b2c3d # вміст у зручному вигляді
git cat-file -e a1b2c3d # лише перевірити існування (код виходу)
Подорож від коміту до файлу:
git cat-file -p HEAD
# tree 3c4e9cd...
# parent 84ba035...
# ...
git cat-file -p 3c4e9cd # кореневе дерево
# 100644 blob 1f7a7a4... composer.json
# 040000 tree 8e2b7f1... app
git cat-file -p 8e2b7f1 # дерево каталогу app/
git cat-file -p HEAD:composer.json # одразу вміст файлу в коміті
Blob - лише вміст файлу. У ньому немає імені, прав чи дати: файли з однаковим вмістом у різних місцях і різних комітах - один blob. Перейменування файлу не створює нового blob-а, лише змінює запис у tree.
Хеш blob-а - SHA-1 від заголовка й вмісту: blob <розмір>\0<вміст>. Тому його можна обчислити й без Git:
printf 'Hello\n' | git hash-object --stdin
printf 'blob 6\0Hello\n' | shasum
# обидві команди дають e965047ad7c57865823c7d992b1d046ea66edf78
Tree - відсортований список записів режим тип хеш ім'я. Він відповідає одному каталогу й посилається на blob-и (файли) і інші tree (підкаталоги).
Що випливає зі структури:
- зміна одного файлу в глибокому каталозі створює новий blob, нові tree для кожного каталогу на шляху до кореня й новий коміт. Усі інші tree й blob-и перевикористовуються - коміт великого проєкту з однією зміною займає кілька сотень байтів;
- порівняння двох комітів дешеве: однакові хеші піддерев означають однакові каталоги, і Git не заходить у них;
- ім'я і вміст розділені, тож Git дізнається про перейменування лише порівнянням.
Масова робота: git cat-file --batch і --batch-check читають багато об'єктів за один процес - так працюють інструменти аналізу репозиторіїв (git cat-file --batch-all-objects --batch-check - перелік усіх об'єктів з розмірами, щоб знайти найбільші).