BorisovAI
Все публикации
Исправлениеai-agents-genkitGit коммит

Как git push --force-with-lease спасает CI от зацикливания на release-ветках

Как git push --force-with-lease спасает CI от зацикливания на release-ветках

Работаем над genkit — платформой для AI-агентов от Google. В проекте есть автоматическая система выпуска релизов, которая живёт в releasekit-uv.yml и должна была работать как часы. Но в какой-то момент CI начал падать с ошибкой non-fast-forward при попытке создать PR для релиза.

Проблема: ветка, которая не отпускает

Корень зла оказался простым, но коварным. Функция prepare_release() каждый раз пересоздаёт release-ветку с нуля, используя git checkout -B. Это нормально, если ветка только локальная. Но когда она уже существует на удалённом репозитории (остаток от прошлого запуска CI), git push отказывается её обновлять — это же non-fast-forward изменение, потенциально опасное.

Ситуация усугублялась тем, что CI часто запускается повторно: разработчик запустил релиз, что-то пошло не так, и он попытался снова. На втором прогоне releasekit уже видит старую ветку на origin и падает.

Решение: force с умом

Мы добавили параметр force: bool = False в протокол VCS — это общий интерфейс, который поддерживают и Git, и Mercurial. В реализации для Git выбрали --force-with-lease вместо обычного --force.

Почему именно --force-with-lease? Потому что это безопаснее. Обычный --force перезапишет любую историю на удалённом сервере, даже если её там уже изменили руки коллеги. --force-with-lease проверит: “Удалённая ветка ещё в том состоянии, которое я последний раз видел?” Если нет — откажет. Это защита от случайного стирания чужой работы.

В prepare.py теперь вызываем:

vcs.push(force=True)

И выполненных тестов говорят, что всё работает: ruff check, py type check, pyrefly check — все зелёные.

Заодно навели чистоту

Улучшили обработку ошибок в cli.py — теперь _cmd_prepare ловит RuntimeError и логирует событие prepare_error вместо полного traceback’а. А в GitHub Actions улучшили читаемость: если что-то сломалось, выводим последние 50 строк логов вне группы ::group::, чтобы видно было сразу, без разворачивания.

Бонус: переписали скрипт setup.sh — заменили медленный O(M×N) цикл с grep’ом на быструю O(M+N) ассоциативную таблицу для проверки уже загруженных моделей Ollama. Мелочь, но помогает ускорить инициализацию.

Вывод

Иногда самые коварные баги скрывают простые решения: просто нужно знать нужный флаг Git и немного поработать над безопасностью. Теперь release-ветки пересоздаются без конфликтов, CI стабилен, и разработчики могут перезапускать подготовку релизов столько раз, сколько нужно.


Что общего у Selenium и подростка? Оба непредсказуемы и требуют постоянного внимания. 😄

Метаданные

Branch:
main
Dev Joke
Что общего у Selenium и подростка? Оба непредсказуемы и требуют постоянного внимания

Оцените материал

0/1000