vulp

Терминальный инструмент для управления многими репозиториями сразу. Из одного места показывает состояние всего workspace, делает batch-sync, ведет PR, issue и статистику вкладов. Имеет TUI-поверхность для людей и беспромптовый JSON CLI для скриптов и автоматизации.

vulp
TL;DR

vulp - это единый интерфейс ко всей мастерской репозиториев: десятки репозиториев, одно и то же состояние и одни и те же операции пакетно. Внизу лежит единое ядро, а сверху два входа - CLI без промптов с выводом JSON для скриптов и полноэкранный TUI для человека. Guardrails следят за тем, чтобы вы не запушили что-то не туда, а обнаружение расхождений сравнивает каждый репозиторий с его зеркалом на сервере.

Введение

vulp вырос из нашей собственной мастерской, а не из идеи продукта. Мы ведём десятки репозиториев одновременно - бренды, панели, боты, инструменты - и в какой-то момент одно только удержание в голове того, какой репозиторий ждёт коммита, а какой пуша, стало стоить дороже самой работы. Обычный git прекрасен для одного репозитория и совершенно беспомощен против тридцати сразу.

Поэтому мы построили инструмент, который относится ко всему рабочему пространству как к единому целому: он сканирует каждый репозиторий за один проход, сводит их состояние в одну таблицу и позволяет выполнить одну и ту же операцию сразу над многими. Одно жёсткое условие мы поставили с самого начала - тот же инструмент должен служить и человеку за клавиатурой, и скрипту в CI, без двух отдельных кодовых баз для сопровождения.

Тридцать репозиториев, один цикл кликов

Когда вы ведёте один репозиторий, обычного git вполне достаточно. При тридцати начинается ритуал: зайти в каталог, проверить ветку, посмотреть, чист ли рабочий каталог, проверить, опережаете ли вы удалённый, назад, следующий. Пока охватите состояние всего, проходит четверть часа, и всё равно легко упустить тот единственный репозиторий, в котором лежат незапушенные изменения двухдневной давности.

Хуже всего то, что эти затраты растут линейно с числом репозиториев, а человеческое внимание - нет. Чем больше каталогов обходить, тем выше шанс, что один пропустите - и обычно именно тот, в котором что-то висит. Цикл в shell по каталогам немного помогает, но каждый такой цикл - это ещё один скрипт, который надо написать и сопровождать, переписываемый заново каждый раз, когда нужна другая операция.

vulp собирает это состояние в одно место и позволяет сделать одно и то же над многими репозиториями одной командой. Вместо тридцати вызовов git status вы получаете одну таблицу, а вместо цикла по каталогам - одну команду с ясной областью действия.

1
Скан рабочего пространства

один проход по каждому репозиторию собирает ветку, чистоту рабочего каталога и на сколько коммитов вы опережаете удалённый или отстаёте от него.

2
Сводный вид

состояние всего попадает в одну таблицу, отсортированную так, что требующее внимания оказывается наверху.

3
Пакетная операция

коммит и пуш проходят по выбранным репозиториям одной командой, а не каталог за каталогом.

4
Проверка

после операции vulp сравнивает локальное состояние с зеркалом на сервере и показывает расхождение деплоя.

Одно ядро, два входа

Самое важное архитектурное решение было принято в самом начале: вся логика живёт в ядре, а CLI и TUI - лишь две оболочки над одним и тем же. CLI без промптов и возвращает JSON, поэтому встраивается в скрипты и CI без разбора текста, написанного для людей. TUI даёт то же знание человеку, который предпочитает смотреть на таблицу, а не помнить флаги.

Благодаря этому новая операция появляется сразу в обоих местах. Вы пишете её один раз, в ядре, и скрипт в cron, и человек по нажатию клавиши получают ровно одно и то же поведение - с теми же предохранителями. Исчезает целый класс расхождений в духе "из-под руки работает иначе, чем из пайплайна".

sync-all.sh · bash
vulp status --json > state.json

vulp sync --push --only-ahead --require-clean

Guardrails, которые предпочитают отказать

Флаг, требующий чистого рабочего каталога, - не каприз. Без него пакетный пуш может отправить половину недоделанной работы вместе с готовой - и на тридцати репозиториях сразу, так что ошибку не откатить одним движением. Guardrails в vulp по умолчанию консервативны: нам лучше, чтобы инструмент отказал и потребовал явности, чем чтобы он молча сделал что-то необратимое.

Тот же принцип действует при массовых операциях. Пуш в защищённую ветку, пуш в репозиторий, опережающий локальное состояние, коммит с грязным рабочим каталогом там, где его быть не должно - всё это вещи, на которых инструмент должен остановиться и спросить, а не угадывать намерение. Автоматизация без тормозов быстрее ровно до первой ошибки.

!
Внимание

Пакетная операция над десятками репозиториев так же быстра в добре, как и во зле. Один плохой пуш умножается на число репозиториев, поэтому guardrails здесь - не чрезмерная осторожность, а условие, при котором мы вообще допускаем пакетные операции. По умолчанию блокировать, для исключения требовать явный флаг.

Расхождение с зеркалом на сервере

Сам пуш - ещё не конец истории; важно то, что реально стоит на сервере. Мы держим там зеркало репозиториев, и после операции vulp сравнивает локальное состояние с этим зеркалом и показывает, где код в репозитории разошёлся с тем, что на самом деле развёрнуто. Это ловит классическую ловушку: изменение закоммичено и запушено, но никогда не развёрнуто, поэтому живёт только в git.

К этому добавляется ежедневная работа вокруг репозиториев, которая тоже идёт через тот же инструмент: просмотр PR, issue и статистики вклада. Вместо того чтобы открывать браузер для каждого репозитория по отдельности, вы видите всё сводно, там же, где и так смотрите на состояние рабочего пространства.

Вручную против vulp

ДействиеВручную, репозиторий за репозиториемЧерез vulp
Проверка состояниятридцать заходов и git statusодин проход, одна таблица
Пуш готовогоцикл по каталогамодна команда с областью действия
Защита от плохого пушапамять и вниманиеguardrails в ядре
Расхождение деплояузнаёте, когда что-то падаетсравнение с зеркалом после операции

Что от этого остаётся

Эффект скучен в лучшем смысле слова: проверка состояния рабочего пространства и пуш готового перестали быть утренним ритуалом кликов. Осталась одна команда, которую можно запустить из-под руки или запланировать и забыть - с теми же предохранителями в обоих случаях.

Более глубокий выигрыш в том, что инструмент масштабируется вместе с числом репозиториев, а не против него. Двадцатый репозиторий не добавляет ритуала, потому что вся мастерская всё равно обходится за один проход. Новая операция - это правка в ядре, которую получают и CLI, и TUI, и скрипт CI - одним коммитом, без расхождения версий.

30+
репозиториев под одной командой
1
ядро, два входа вместо двух кодовых баз
0
промптов в режиме CI

Но самое важное - vulp не отдельный гаджет рядом с нашей работой, а тот же слой, через который проходят и рука, и автомат. Человек кликает, cron срабатывает, и они делают ровно одно и то же, столь же безопасно. В этом и разница между скриптом, который работает у автора, и инструментом, на который можно полагаться каждый день.

Больше проектов

Другие работы из той же категории - посмотрите, как мы решаем похожие задачи.

Есть похожий проект?

Напишите нам - смета бесплатна и приходит в течение часа.