Git - как перечислить ВСЕ объекты в базе данных
Есть ли лучший способ получить необработанный список SHA1 для ВСЕХ объектов в хранилище, чем делать ls .git/objects/??/\*
а также cat .git/objects/pack/*.idx | git show-index
?
Я знаю о git rev-list --all
но это только перечисляет объекты коммитов, на которые ссылаются.git / refs, и я ищу все, включая объекты без ссылок, которые создаются git-hash-object, git-mktree и т. д.
8 ответов
Изменить: Aristotle Pagaltzis опубликовал еще лучший ответ, который должен быть помечен как правильный.
Ответ Марка сработал для меня после нескольких модификаций:
- Используемый
--git-dir
вместо--show-cdup
поддерживать голые репо - Предотвращена ошибка, когда нет пакетов
- Используемый
perl
потому что OS X Mountain Lion в стиле BSDsed
не поддерживает-r
#!/bin/sh
set -e
cd "$(git rev-parse --git-dir)"
# Find all the objects that are in packs:
find objects/pack -name 'pack-*.idx' | while read p ; do
git show-index < $p | cut -f 2 -d ' '
done
# And now find all loose objects:
find objects/ \
| egrep '[0-9a-f]{38}' \
| grep -v /pack/
| perl -pe 's:^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}):\1\2:' \
;
Пытаться
git rev-list --objects --all
Править Джош сделал хорошую мысль:
git rev-list --objects -g --no-walk --all
список объектов, доступных из ref-журналов.
Чтобы увидеть все объекты также в недоступных коммитах:
git rev-list --objects --no-walk \
$(git fsck --unreachable |
grep '^unreachable commit' |
cut -d' ' -f3)
Собрав все это вместе, чтобы действительно получить все объекты в выходном формате rev-list --objects
вам нужно что-то вроде
{
git rev-list --objects --all
git rev-list --objects -g --no-walk --all
git rev-list --objects --no-walk \
$(git fsck --unreachable |
grep '^unreachable commit' |
cut -d' ' -f3)
} | sort | uniq
Чтобы отсортировать вывод немного более полезным способом (по пути для дерева / больших двоичных объектов, сначала фиксирует), используйте дополнительный | sort -k2
который сгруппирует все различные BLOB-объекты (ревизии) для идентичных путей.
Я не знаю с тех пор, когда эта опция существует, но вы можете
git cat-file --batch-check --batch-all-objects
Это дает вам, согласно странице руководства,
все объекты в хранилище и любые альтернативные хранилища объектов (не только достижимые объекты)
(акцент мой).
По умолчанию это дает тип объекта и его размер вместе с каждым хешем, но вы можете легко удалить эту информацию, например, с помощью
git cat-file --batch-check --batch-all-objects | cut -d' ' -f1
или предоставив пользовательский формат --batch-check
,
git cat-file --batch-check --batch-all-objects
Команда, предложенная в ответе Erki der Loony, может быть выполнена быстрее с новой опцией Git 2.19 (Q3 2018) --unordered
,
API для итерации по всем изученным объектам для необязательного перечисления объектов в порядке их появления в пакетных файлах, что помогает обеспечить локальность доступа, если вызывающая сторона обращается к этим объектам, когда перечисляются объекты.
См. Коммит 0889aae, коммит 79ed0a5, коммит 54d2f0d, коммит ced9fff (14 августа 2018 г.) и коммит 0750bb5, коммит b1adb38, коммит aa2f5ef, коммит 736eb88, коммит 8b36155, коммит a7ff6f5, коммит 202e7f1 (10 авг 2018) от Jeff King peff
) (Объединено Юнио С Хамано - gitster
- в коммите 0c54cda, 20 августа 2018 г.)
cat-file
: служба поддержки "unordered
"выход для--batch-all-objects
Если вы собираетесь получить доступ к содержимому каждого объекта в файле пакета, как правило, гораздо эффективнее сделать это в порядке упаковки, а не в порядке хэширования. Это увеличивает локальность доступа в файле пакета, что, в свою очередь, более удобно для кеша дельта-базы, так как файл пакета размещает связанные дельты рядом друг с другом. В отличие от этого, порядок хеширования фактически является случайным, поскольку sha1 не имеет заметной связи с контентом.
Этот патч вводит "
--unordered
вариантcat-file
который перебирает пачки в порядке-упаковке под капотом. Вы можете увидеть результаты при выгрузке всего содержимого файла:$ time ./git cat-file --batch-all-objects --buffer --batch | wc -c 6883195596 real 0m44.491s user 0m42.902s sys 0m5.230s $ time ./git cat-file --unordered \ --batch-all-objects --buffer --batch | wc -c 6883195596 real 0m6.075s user 0m4.774s sys 0m3.548s
Тот же вывод, другой порядок, намного быстрее. Такое же ускорение применяется, даже если вы в конечном итоге получаете доступ к содержимому объекта в другом процессе, например:
git cat-file --batch-all-objects --buffer --batch-check | grep blob | git cat-file --batch='%(objectname) %(rest)' | wc -c
Добавление "
--unordered
"до первой команды сбрасывает время выполнения вgit.git
от 24 до 3,5 с.Примечание: на самом деле теперь доступны дополнительные ускорения для выполнения всего этого в процессе. Поскольку мы выводим содержимое объекта во время фактической итерации пакета, мы знаем, где найти объект, и можем пропустить дополнительный поиск, выполненный
oid_object_info()
, Этот патч не дотягивает до этой оптимизации, так как базовый API не готов к тому, чтобы мы делали такие прямые запросы.Так что если
--unordered
это намного лучше, почему бы не сделать его по умолчанию? Две причины:
Мы обещали в документации, что
--batch-all-objects
выводит в порядке хэша. посколькуcat-file
водопровод, люди могут полагаться на этот дефолт, и мы не можем его изменить.Это на самом деле медленнее в некоторых случаях. Мы должны вычислить пакет revindex, чтобы пройти в порядке упаковки. И наш шаг дедупликации использует oidset, а не сортировку и дедупликацию, которая может оказаться более дорогой.
Если мы просто обращаемся к типу и размеру каждого объекта, например:
git cat-file --batch-all-objects --buffer --batch-check
мой лучший из пяти тайников тайминга кеша от 900мс до 1100мс с использованием
--unordered
, Хотя возможно в холодном кэше или под давлением памяти мы могли бы добиться большего успеха, так как у нас была бы лучшая локальность в пакете.И последний вопрос: почему это так?
--unordered
" и не "--pack-order
"Ответ опять двоякий:
"порядок упаковки" не является четко определенной вещью для всего набора объектов. Мы наносим удары по незакрепленным объектам, а также объектам в нескольких пакетах, и единственный обещаемый нами порядок находится в одном пакете. Остальное, по-видимому, случайно.
Дело здесь в оптимизации. Таким образом, мы не хотим обещать какой-либо конкретный порядок, а только сказать, что мы выберем порядок, который, вероятно, будет эффективным для доступа к содержимому объекта. Это оставляет дверь открытой для дальнейших изменений в будущем без необходимости добавления другого варианта совместимости.
Это даже быстрее в Git 2.20 (Q4 2018) с:
См. Коммит 8c84ae6, коммит 8b2f8cb, коммит 9249ca2, коммит 22a1646, коммит bf73282 (04 октября 2018 г.) от René Scharfe ( rscharfe
)
(Объединено Юнио С Хамано - gitster
- в коммите 82d0a8c, 19 октября 2018 г.)
oidset
: использоватьkhash
Перепишите
oidset
с помощьюkhash.h
чтобы уменьшить объем памяти и сделать ее быстрее.Выполнение команды, которая в основном проверяет дубликаты объектов с помощью oidset, с
master
и Clang 6.0.1:$ cmd="./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)'" $ /usr/bin/time $cmd >/dev/null 0.22user 0.03system 0:00.25elapsed 99%CPU (0avgtext+0avgdata 48484maxresident)k 0inputs+0outputs (0major+11204minor)pagefaults 0swaps $ hyperfine "$cmd" Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)' Time (mean ± σ): 250.0 ms ± 6.0 ms [User: 225.9 ms, System: 23.6 ms] Range (min … max): 242.0 ms … 261.1 ms
И с этим патчем:
$ /usr/bin/time $cmd >/dev/null 0.14user 0.00system 0:00.15elapsed 100%CPU (0avgtext+0avgdata 41396maxresident)k 0inputs+0outputs (0major+8318minor)pagefaults 0swaps $ hyperfine "$cmd" Benchmark #1: ./git-cat-file --batch-all-objects --unordered --buffer --batch-check='%(objectname)' Time (mean ± σ): 151.9 ms ± 4.9 ms [User: 130.5 ms, System: 21.2 ms] Range (min … max): 148.2 ms … 170.4 ms
Это более правильное, более простое и быстрое исполнение сценария из ответов Марка и Уилкилла.
Оно использует
rev-parse --git-path
найтиobjects
каталог даже в более сложной настройке Git-репозитория (например, в ситуации с несколькими рабочими деревьями или еще чем-то).Это позволяет избежать ненужного использования
find
,grep
,perl
,sed
,Если работает изящно, даже если у вас нет незакрепленных объектов или пакетов (или ни того, ни другого... если вы склонны запускать это в новом хранилище).
Это, однако, требует Bash из этого тысячелетия (2.02 или новее, особенно для
extglob
немного).
Поделитесь и наслаждайтесь.
#!/bin/bash
set -e
shopt -s nullglob extglob
cd "`git rev-parse --git-path objects`"
# packed objects
for p in pack/pack-*([0-9a-f]).idx ; do
git show-index < $p | cut -f 2 -d ' '
done
# loose objects
for o in [0-9a-f][0-9a-f]/*([0-9a-f]) ; do
echo ${o/\/}
done
Я не знаю явно лучшего способа, чем просто смотреть на все свободные объектные файлы и индексы всех файлов пакета. Формат репозитория git очень стабилен, и с этим методом вам не нужно полагаться на наличие правильных опций git fsck
, который классифицируется как фарфор. Я думаю, что этот метод быстрее. Следующий скрипт показывает все объекты в репозитории:
#!/bin/sh
set -e
cd "$(git rev-parse --show-cdup)"
# Find all the objects that are in packs:
for p in .git/objects/pack/pack-*.idx
do
git show-index < $p | cut -f 2 -d ' '
done
# And now find all loose objects:
find .git/objects/ | egrep '[0-9a-f]{38}' | \
sed -r 's,^.*([0-9a-f][0-9a-f])/([0-9a-f]{38}),\1\2,'
(Моя оригинальная версия этого скрипта была основана на этом полезном скрипте для поиска самых больших объектов в ваших пакетных файлах, но я переключился на использование git show-index
, как предложено в вашем вопросе.)
Я сделал этот скрипт в GitHub Gist.
Еще одна полезная опция заключается в использовании git verify-pack -v <packfile>
verify-pack -v
перечисляет все объекты в базе данных вместе с их типом объекта.
Комбинируя Erki der Loony и sehe решение, мы можем получить почти все имена файлов объектов blob (за исключением файлов, исключенных в git):
git cat-file --batch-check --batch-all-objects | grep blob | cut -d" " -f1 | xargs -n1 git rev-list --objects -g --no-walk --all > .recovered/allblobobject.txt
cat .recovered/allblobobject.txt | sort | uniq > .recovered/allblobuniqobject.txt
Эту карту имен файлов и больших двоичных объектов можно использовать для восстановления исчезнувших файлов, полученных с помощью:
git fsck --full --no-reflogs --unreachable --lost-found | grep blob | cut -d" " -f3 > .recovered/bloblist.txt
for /F "tokens=*" %A in (.recovered/bloblist.txt) do (git cat-file -p %A > .recovered/%A)