Git - как составить список ВСЕХ объектов в базе данных

StackOverflow https://stackoverflow.com/questions/7348698

  •  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 в стиле BSD sed не поддерживает -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 это намного лучше, почему бы не сделать это по умолчанию?Две причины:

  1. Мы обещали в документации, что --batch-all-objects выводит данные в порядке хэширования.С тех пор как cat-file это водопровод, люди могут полагаться на это значение по умолчанию, и мы не можем его изменить.

  2. Это на самом деле медленнее для некоторых случаев.Мы должны вычислить revindex пакета, чтобы ходить в порядке следования пакетов.И на нашем этапе дедупликации используется oidset, а не sort-and-dedup, что в конечном итоге может обойтись дороже.

Если мы просто получаем доступ к типу и размеру каждого объекта, например, как:

git cat-file --batch-all-objects --buffer --batch-check

мои лучшие из пяти таймингов прогрева кэша варьируются от 900 мс до 1100 мс с использованием --unordered.Хотя возможно, что в холодном кэше или при нехватке памяти мы могли бы добиться большего, поскольку у нас была бы лучшая локальность внутри файла пакета.

И последний вопрос:почему это "--unordered" и не "--pack-order"?Ответ опять же двоякий:

  1. "порядок упаковки" не является четко определенной вещью для всего набора объектов.Мы подбираем свободные предметы, а также предметы в нескольких упаковках, и единственный порядок, который мы обещаем, это внутри одна упаковка.Остальное, по-видимому, является случайным.

  2. Дело здесь в оптимизации.Таким образом, мы не хотим обещать какой-либо конкретный порядок, а только сказать, что мы выберем порядок, который, вероятно, будет эффективным для доступа к содержимому объекта.Это оставляет дверь открытой для дальнейших изменений в будущем без необходимости добавлять еще один параметр совместимости


Это еще быстрее в 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 перечисляет все объекты в базе данных вместе с типом объекта.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top