Итак, есть десятки способов взаимодействия с репозиторием GitHub. Методы включают Github GraphQL, GitHub REST API, git clone/fetch
-ing и прямое взаимодействие с базовыми службами Github.
Я нашел различные способы формирования дерева коммитов SHA, но почти каждый метод, который я нашел, имеет неэффективность, которую я не могу решить.
Я просто хочу найти SHA общего предка двух ветвей.
Ветки в git подобны указателям на коммит shas. Сама ветка на самом деле не отслеживает, какие коммиты находятся в ветке, а только какие коммиты находятся на кончике ветки. Затем коммиты отслеживают своих родителей. Таким образом, обычный способ определить общего предка двух ветвей состоит в том, чтобы перебирать каждую родительскую фиксацию, начиная с кончика ветки, пока вы не найдете фиксацию, которая является общей для обеих ветвей. Вот как работает git merge-base
.
Проблема с git merge-base
в том, что вам нужно как минимум выполнить git fetch
в хранилище. Это неэффективно, потому что git fetch
загружает больше, чем просто SHA коммита из источника.
Итак, я думал об использовании GitHub REST и/или API GraphQL. Проблема с обоими:
Конкретный репозиторий, который я пытаюсь запустить merge-base
, — это chromium/chromium, который является абсолютно огромным репозиторием.
Я пытаюсь найти общих предков основной ветки и веток функций, связанных с каждым тегом Git. Звучит довольно просто, за исключением того факта, что в репозитории chromium/chromium есть почти 27 000 тегов и связанных с ними веток функций.
Таким образом, с учетом сказанного, попытка вручную запустить базу слияния в репозитории с помощью простого запроса GraphQL по-прежнему слишком неэффективна. С ограничением скорости 500 000 (5000 баллов) при 27 000 ветвей функций я теоретически мог бы выполнить только более 20 коммитов на ветвь, прежде чем достичь ограничения скорости GraphQL. Что еще хуже, я ожидаю, что количество тегов в этом репозитории со временем будет увеличиваться.
О REST не может быть и речи (насколько мне известно во всяком случае), потому что ограничения скорости для REST еще более ограничительны.
Я не уверен, есть ли способ оптимизировать описанные выше методы, но я также рассматривал возможность взаимодействия с базовыми службами связи.
Я считаю, что git взаимодействует на прикладном уровне, используя HTTP для связи с репозиториями с пользовательскими заголовками HTTP. Этот метод позволил бы мне взаимодействовать не только с зеркалом GitHub Chromium, , но и с реальным репозиторием, размещенным Piper/Gitiles .
Однако я не уверен, есть ли способ вручную объединить базу с этим. Мне было интересно, можно ли просто загрузить SHA фиксации (и их родителей) с учетом целевой ветки и без других метаданных, но я понятия не имел, как это сделать и будет ли это эффективно. Кажется, я не могу найти никакой хорошей документации по базовым службам связи, предлагаемым репозиториями git.
На моей машине это занимает около минуты:
git clone --bare --filter=tree:0 https://github.com/chromium/chromium chromium-bare
Сейчас репозиторий занимает около 764M.
--filter=tree:0
избегает деревьев и капель (предложено Бенджамином
В. ). --bare
означает, что нам не нужно проверять рабочее дерево.
Это занимает 19 секунд:
git commit-graph write
Попробуем найти старый тег:
git tag --sort=version:refname
Я не знаю, какая версия у Chromium, поэтому я просто предполагаю, что эти
теги могут быть отсортированы таким образом. Тег 3.0.195.25
с 2014 года.
Это занимает около 1,3 с:
git merge-base main 3.0.195.25
Допустим, это худший случай. С примерно 27 000 тегов он должен
потребуется не более 1.3 * 27000 = 35100
секунд, чтобы вычислить все слияния
базы (при условии, что время выполнения остального кода незначительно),
или 9¾ часов.
xargs
с (GNU) parallel
Вычисление базы слияния между master
и двумя сотнями тегов занимает
около 2м18с:
git for-each-ref --format='%(refname:short)' 'refs/tags/**' --count=200 | xargs -n 1 git merge-base master
Я разогрел диск (надеюсь), выполнив команду один раз перед призывом.
Та же процедура с parallel
вместо этого:
git for-each-ref --format='%(refname:short)' 'refs/tags/**' --count=200 | parallel -n 1 git merge-base master
Это занимает 28 секунд.
Мой процессор имеет четыре ядра и восемь потоков.
Это сокращает общее время работы с 9¾ часов до примерно 1 часа 10 минут.