В современном мире разработки программного обеспечения каждое изменение кода требует тщательного контроля качества. Автоматизация процессов проверки становится залогом стабильной работы и ускорения цикла разработки. Одним из важных этапов является проверка кода перед выкладкой в удаленный репозиторий — предвыкладочные проверки (pre-push checks). В этой статье мы подробно рассмотрим, как автоматизировать этот процесс с помощью современного инструмента управления версиями Jujutsu, сочетающего в себе удобство и функциональность, и интегрировать его с популярным инструментом для проверки кода pre-commit. Jujutsu (часто сокращенно jj) представляется собой новую систему контроля версий, которая избавляет от многих сложностей, с которыми сталкиваются разработчики при использовании Git.
Автор статьи, опробовавший Jujutsu, отмечает, что эта система устраняет такие боли, как конфликты слияния и необходимость ручного ребейза, а также убирает усложняющие жизнь подкоманды Git. При этом Jujutsu может работать как дополнение к Git, позволяя использовать его в существующих проектах без проблем с совместимостью и влияния на других участников команды. Однако, несмотря на массу преимуществ, Jujutsu пока не поддерживает систему хуков на уровне самого инструмента. Хуки — это скрипты, которые автоматически выполняются при определенных действиях с репозиторием, например, перед коммитом или пушем. Многие разработчики используют предкоммитные хуки, настроенные с помощью утилиты pre-commit, для автоматического линтинга, форматирования и проверки типов в своем коде.
Этот подход позволяет ловить ошибки локально до того, как они попадут в систему CI, экономя время и ресурсы. Чтобы решить проблему отсутствия нативной поддержки хуков в Jujutsu, разработчик применил хитрый обходной путь — создание собственных команд-алиасов с использованием встроенной системы алиасов Jujutsu. Эта возможность позволяет запускать произвольные bash-скрипты через команду jj util exec, что открывает широкие возможности для автоматизации. Первым шагом был запуск предкоммитных проверок при совершении коммита. Для этого автор создал алиас commit-with-checks, который сначала запускает pre-commit с передачей списка измененных файлов, а затем, если проверки прошли успешно, выполняет собственно коммит через Jujutsu.
Поскольку в Jujutsu отсутствует индексирование и стадия, как в Git, пришлось динамически получать список измененных файлов при помощи команды jj diff --name-only -r @ и передавать их в pre-commit через опцию --files. Такой подход позволяет эффективно анализировать только те файлы, что были реально изменены, а не весь проект, экономя время выполнения проверок. Проверки, таким образом, стали обязательным условием для совершения коммита, предотвращая попадание некорректного кода в историю изменений. В случае, если pre-commit находит ошибки, commit-with-checks исправляет их (например, удаляет неиспользуемые импорты или форматирует код), после чего необходимо повторно выполнить команду коммита. Это именно тот уровень контроля качества, который необходим в современном разработческом процессе.
Однако представленная схема имеет ограничения. В модели Jujutsu коммиты создаются и меняются более динамично — их можно править, перемещать и объединять без особых усилий, что иногда делает запуск проверок на каждом коммите излишним и даже мешающим гибкости работы. К тому же, есть риск не запустить проверки при изменениях, выполненных не через commit-with-checks, либо при иных операциях, как squash или describe. Таким образом, автор пришел к выводу, что более целесообразным является запуск предвыкладочных проверок перед выполнением push — единственный момент, когда изменения отправляются в общий репозиторий, и где важно гарантировать качество кода. Одна из основных задач — определить, какие именно коммиты будут отправлены, чтобы запустить проверки именно на этих ревизиях, а не на локальной рабочей копии.
Для этого была составлена специальная команда push-with-checks, которая сначала получает все изменения между текущей локальной отметкой (букмарком) и удаленным репозиторием с помощью команды jj log с кастомным шаблоном вывода. Затем из этого списка берутся крайние коммиты (from_ref и to_ref), которые передаются в pre-commit параметры --from-ref и --to-ref. Это дает возможность запускать проверки по конкретным ревизиям, а не по всем файлам целиком. После успешного прохождения проверок выполняется команда git push, интегрированная в Jujutsu через jj git push. Этот подход позволил решить проблему попадания непроверенного кода в удаленный репозиторий.
При нахождении ошибок pre-commit может автоматически их исправить, внося изменения в рабочую копию. В таком случае требуется выполнить операцию squash, чтобы объединить исправления с предыдущим коммитом, что поддерживает чистоту истории версий. Несмотря на успешность реализации, автор отмечает ряд ограничений. Например, команда push-with-checks настроена исключительно под работу с удаленным репозиторием по умолчанию origin и одним активным букмарком. В более сложных сценариях с несколькими удаленными репозиториями или одновременно обновляемыми ветками необходима доработка реализации.
Кроме того, пользователю необходимо помнить о необходимости применять именно эту команду push-with-checks, а не стандартный push, чтобы гарантировать выполнение проверок. В качестве дальнейшего развития был упомянут сторонний Python-пакет jj-pre-push, разработанный сообществом. Он выполняет имитацию push (dry-run), чтобы точно определить набор коммитов и параметров, подлежащих проверке, что обеспечивает более высокую точность и поддержку разных вариантов использования, включая работу с несколькими букмарками и удаленными источниками. Использование jj-pre-push с pre-commit делает процесс интеграции удобным и расширяемым. Jujutsu в сочетании с pre-commit и таким инструментом, как jj-pre-push, открывает новый взгляд на контроль качества кода в распределенных системах управления версиями.
Автоматизация предвыкладочных проверок помогает сохранить высокие стандарты разработки, минимизировать вероятность ошибок и сократить время на отладку CI. Использование Jujutsu также меняет восприятие самого процесса коммитов. Поскольку система не требует обязательного индексирования и позволяет динамически изменять историю, разработчик получает свободу в организации своей работы. Вместо того чтобы бояться конфликтов и сложных процессов слияния, он может сосредоточиться на написании качественного кода и контроле над конечным результатом перед отправкой изменений. В итоге, несмотря на то что Jujutsu пока находится в стадии активной разработки и не имеет встроенной поддержки хуков, приведенные методы позволяют эффективно реализовать практики, традиционно базирующиеся на Git.
Автоматизация составляет важный элемент современного DevOps-подхода, а грамотное сочетание новых инструментов способствует росту продуктивности команд и снижению дорогостоящих ошибок. Для разработчиков Python особенно полезно применять uv для настройки виртуальных окружений и управления зависимостями в своих проектах вместе с pre-commit и Jujutsu, что обеспечивает согласованность и воспроизводимость среды при работе в команде. Поддержка шаблонов конфигурации и запуск линтеров, таких как ruff, с автоматическим исправлением ошибок стал неотъемлемой частью ежедневного рабочего процесса. Таким образом, автоматизация предвыкладочных проверок с помощью Jujutsu и pre-commit не только повышает надежность кода, но и трансформирует процесс разработки, делая его более плавным и комфортным. Внедрение таких решений в реальные проекты предоставляет конкурентное преимущество и снижает технический долг.
В будущем с развитием Jujutsu и появлением встроенной поддержки хуков данная область обещает стать еще более удобной и мощной.