Git - как составить список ВСЕХ объектов в базе данных
-
27-10-2019 - |
Вопрос
Есть ли лучший способ получить необработанный список SHA1 для ВСЕХ объектов в репозитории, чем выполнение ls .git/objects/??/\*
и cat .git/objects/pack/*.idx | git show-index
?
Я знаю о git rev-list --all
но в нем перечислены только объекты фиксации, на которые ссылается .git/refs, и я ищу все включая объекты без ссылок, которые создаются с помощью git-hash-object, git-mktree и т.д.
Решение
Редактировать: Аристотель Опубликовано Еще лучший ответ, что должно быть отмечено как правильное.
Редактировать: Сценарий содержал синтаксис grep -v
линия
Ответ Марка сработал для меня после нескольких модификаций:
- Использовал
--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
Список объектов, достижимых из рефлексии.
Чтобы увидеть все объекты в недоступных коммитах:
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
который будет сгруппировать все разные капли (пересмотров) для одинаковых путей.
Я не знаю с тех пор, как этот вариант существует, но вы можете
git cat-file --batch-check --batch-all-objects
Это дает вам, по словам страницы человека,
все объекты в репозитории и в любых альтернативных магазинах объектов (Не только достижимые объекты)
(акцент мой).
По умолчанию это дает тип объекта и его размер вместе с каждым хэшем, но вы можете легко удалить эту информацию, например, с
git cat-file --batch-check --batch-all-objects | cut -d' ' -f1
или давая пользовательский формат --batch-check
.
Это более правильное, проще и более быстрое исполнение сценария из ответов по Марку а также Уилкилл.
Оно использует
rev-parse --git-path
Чтобы найтиobjects
каталог даже в более сложной репозитории GIT (например, в ситуации с несколькими работами или еще много чего).Это избегает всего ненужного использования
find
,grep
,perl
,sed
.Если изящно работает, даже если у вас нет свободных объектов или нет пакетов (или нет ... если вы склонны запускать это в свежем репозитории).
Это, однако, требует удара из этого тысячелетия 😊 (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 cat-file --batch-check --batch-all-objects
команда, предложенная в Erki Der Loony's ответ, может быть сделано быстрее с новой опцией Git 2.19 (3 квартал 2018) --unordered
.
API для перебора всех объектов, изученных для необязательно перечислять объекты в порядке их появления в файлах пакетов, что улучшает локальность доступа, если вызывающая сторона обращается к этим объектам во время перечисления объектов as.
Видишь совершить 0889aae, зафиксировать 79ed0a5, зафиксировать 54d2f0d, зафиксируйте ced9fff (14 августа 2018), и фиксация 0750bb5, зафиксировать b1adb38, зафиксировать aa2f5ef, совершить 736eb88, фиксация 8b36155, зафиксировать a7ff6f5, фиксация 202e7f1 (10 августа 2018) автор Джефф Кинг (peff
).
(Объединено Джунио Си Хамано -- gitster
-- в фиксация 0c54cda, 20 августа 2018)
cat-file
:поддержка "unordered
" вывод для--batch-all-objects
Если вы собираетесь получить доступ к содержимому каждого объекта в файле packfile, как правило, гораздо эффективнее делать это в порядке упаковки, а не в порядке хэширования.Это увеличивает локальность доступа внутри packfile, что, в свою очередь, более удобно для базового кэша дельты, поскольку packfile размещает связанные дельты рядом друг с другом.Напротив, порядок хэширования фактически случайный, поскольку 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, а не sort-and-dedup, что в конечном итоге может обойтись дороже.
Если мы просто получаем доступ к типу и размеру каждого объекта, например, как:
git cat-file --batch-all-objects --buffer --batch-check
мои лучшие из пяти таймингов прогрева кэша варьируются от 900 мс до 1100 мс с использованием
--unordered
.Хотя возможно, что в холодном кэше или при нехватке памяти мы могли бы добиться большего, поскольку у нас была бы лучшая локальность внутри файла пакета.И последний вопрос:почему это "
--unordered
" и не "--pack-order
"?Ответ опять же двоякий:
"порядок упаковки" не является четко определенной вещью для всего набора объектов.Мы подбираем свободные предметы, а также предметы в нескольких упаковках, и единственный порядок, который мы обещаем, это внутри одна упаковка.Остальное, по-видимому, является случайным.
Дело здесь в оптимизации.Таким образом, мы не хотим обещать какой-либо конкретный порядок, а только сказать, что мы выберем порядок, который, вероятно, будет эффективным для доступа к содержимому объекта.Это оставляет дверь открытой для дальнейших изменений в будущем без необходимости добавлять еще один параметр совместимости
Это еще быстрее в Git 2.20 (4 квартал 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
В Git 2.21 (1 квартал 2019) оптимизирует далее в протоколе, чтобы написать фиксации-график, по следуя обычной схеме, посещая объекты в упаковке заказа.
Видишь зафиксировать d7574c9 (19 января 2019) автор Ævar Arnfjörð Bjarmason (avar
).
(Объединено Джунио Си Хамано -- gitster
-- в фиксация 04d67b6, 05 Февраля 2019)
Немного оптимизируйте шаг "фиксация-запись в график", используя
FOR_EACH_OBJECT_PACK_ORDER
сfor_each_object_in_pack()
.
Деррик Стоули так и сделал его собственные тесты на Windows показывает улучшение на 2% с высокой степенью точности.
Улучшен Git 2.23 (3 квартал 2019) "git rev-list --objects
" который научился с помощью "--no-object-names
" опция, позволяющая скрыть путь к объекту, который используется в качестве подсказки группировки для pack-объектов.
Видишь фиксация 42357b4 (19 июня 2019) автор Эмили Шаффер (nasamuffin
).
(Объединено Джунио Си Хамано -- gitster
-- в фиксация f4f7e75, 09 июля 2019)
rev-list
:учить--no-object-names
чтобы включить прокладку трубопроводовУпростить синтаксический анализ с помощью
cat-file
предоставляя rev-list возможность печатать только OID объекта без фиксации без какой-либо дополнительной информации.
Это краткосрочная прокладка;позже,rev-list
должен быть обучен тому, как печатать типы объектов, которые он находит, в формате, подобномcat-file
с.Перед этой фиксацией выходные данные из
rev-list
необходимо помассировать перед отправкой в cat-файл, вот так:git rev-list --objects HEAD | cut -f 1 -d ' ' | git cat-file --batch-check
Это было особенно неожиданно, когда имеешь дело с корнем деревья, как существует невидимый пробел в конце ОИД:
git rev-list --objects --filter=tree:1 --max-count=1 HEAD | xargs -I% echo "AA%AA"
Теперь его можно передавать напрямую, как в добавленном тестовом примере:
git rev-list --objects --no-object-names HEAD | git cat-file --batch-check
Так вот в чем разница между:
vonc@vonvb:~/gits/src/git$ git rev-list --objects HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44
55d368920b2bba16689cb6d4aef2a09e8cfac8ef Documentation
9903384d43ab88f5a124bc667f8d6d3a8bce7dff Documentation/RelNotes
a63204ffe8a040479654c3e44db6c170feca2a58 Documentation/RelNotes/2.23.0.txt
И, с --no-object-name
:
vonc@vonvb:~/gits/src/git$ git rev-list --objects --no-object-names HEAD~1..
9d418600f4d10dcbbfb0b5fdbc71d509e03ba719
590f2375e0f944e3b76a055acd2cb036823d4b44
55d368920b2bba16689cb6d4aef2a09e8cfac8ef
9903384d43ab88f5a124bc667f8d6d3a8bce7dff
a63204ffe8a040479654c3e44db6c170feca2a58
Другой полезный вариант - использовать git verify-pack -v <packfile>
verify-pack -v
перечисляет все объекты в базе данных вместе с типом объекта.