Представьте: ваш Claude Code или Cursor AI-агент удаляет файл или начинает переписывать его заново. Содержимое файла еще не было сохранено в git commit—оно все еще находится в unstaged состоянии. Все потеряно! Стоит только надеяться, что AI-агент сможет что-то восстановить из памяти и контрольных точек, но это костыль, может и не восстановит, а может вы пропустили этот момент.
Когда я переключился с чистого Git на JJ поверх Git, таких проблем и возникнуть не может. Я стал намного спокойнее относиться к своему коду при работе с AI-агентами. Позвольте мне показать, почему JJ улучшит вашу жизнь как программиста и как интегрировать его в вашу практику, не нарушая процессы в команде.
Почему Git не справляется с параллельной разработкой с ИИ
Git фундаментально устарел для систем, в которых код пишется параллельно с вами на вашем ПК.
Парадигма Git проста: вы собираете какие-то изменения локально, кладете их в ящик, ставите на этот ящик хеш-идентификатор и отправляете через конвейер ящиков. Этот ящик вам кажется неизменяемым—лучше его больше не трогать, разве что читать, что в нем сделано. Если что-то произошло, пока вы не собрали ящик, ну напишите еще раз. Обычно вы не ушли далеко, и что может произойти?
В терминах видеоигр, git commit это такие сохранения, которые вы делаете руками. Но вот автосохранений у вас нет.
Годы эта концепция была практически идеальной. Хотя надо признать, интерфейс всех возможностей Git всегда был довольно сложным. Борьба с тем, как выглядит история коммитов в разных компаниях и по сей день говорит, что в этой системе что-то не совсем хорошо.
JJ (Jujutsu) призвана исправить проблемы удобства Git (UX), сохраняя полную совместимость с существующими репозиториями и рабочими процессами.
JJ—это система управления версиями, которая находится поверх Git и предоставляет гораздо более интуитивный интерфейс и богатые возможности для управления историей вашего кода, особенно при работе с AI-агентами.
Позвольте мне показать вам три ключевые концепции, которые делают JJ мощным инструментом:
- JJ log операции: undo и redo
- Рабочая копия как коммит
- Продвинутые операции: squash, split, edit
Часть 1: Операции JJ с Undo/Redo
Поехали, создадим ваш первый JJ-проект:
mkdir jj-step-0 && cd jj-step-0 && jj git init
touch README.md
echo "first try" >> README.md
jj diff
Screenshot (jj diff)

Если выполнить команду jj log, то будет видно, что у вас уже есть Change ID и Commit ID. Слева — Change ID, а справа — Commit ID.
Change ID — это постоянный идентификатор логической задачи, над которой вы работаете. В отличие от Git-хеша (который в jj называется Commit ID), Change ID не меняется, когда вы редактируете файлы, меняете описание и т.п. Change ID никогда не меняется — даже если вы делаете amend, rebase или редактируете сообщение коммита. Основные команды jj edit, jj describe выполняются для выбранной Change ID.
Change ID это случайное число длиной 16 байт, которое представлено цепочкой из 12 символов от z-k. Это делает его вид уникальным и позволяет легко читать.
В jj рабочая директория — это всегда «живой» коммит. Любое изменение в файлах мгновенно становится частью текущей ревизии. Рабочая копия помечается символом @ в выводе jj log. Hash коммита будет меняться при каждом внесении правок в проекте. По этому он не так интересен в процессе работы.
Tip
- Добавить описание к этому коммиту (через jj describe).
- Создать следующий пустой коммит сверху (jj new), чтобы «закрыть» текущий.
- Посмотреть статус файлов, чтобы убедиться, что всё отслеживается (jj status).
jj commit -m "First"
jj
Screenshot (jj first commit)

Наш первый коммит. 🎉🎉🎉 И на данный момент нет никаких изменений в новом рабочем, пора начать писать фичу с помощью AI-агента.
echo "Cool staff" >> README.md
touch new-file.md && echo "One more thing" >> new-file.md
jj diff
Screenshot (jj diff with changes)

Случается страшное: ваш AI-агент решает переписать new-file.md с нуля и удаляет оригинальное содержимое, заменяя его чем-то странным.
Давайте сымитируем то, что сделал AI:
rm new-file.md
touch new-file.md
echo "Bad staff" >> new-file.md
Screenshot (bad changes by AI)

Что делать!?? Точно не будем унижаться перед ИИ и просить его восстановить нашу работу. Вместо этого давайте посмотрим, что сохранил JJ:
jj evolog --color=always -p
Screenshot (jj evolog)

Отлично! JJ сохраняет историю всех изменений в рабочем коммите (тут нету unstaged), а также историю всех операций, которые вы совершили. Каждое изменение, удаление или добавление—это отдельная операция с собственным хешем. Теперь давайте откатим то, что сделал AI:
jj undo
jj diff
Screenshot (jj undo)

Дело сделано. 🎉🎉🎉 И наш "Cool staff" на месте. Если мы вдруг осознаем, что AI был прав, мы можем вернуться с помощью:
jj redo
Важно:
undoиredoработают с операциями, а не с изменениями файлов. Если вы сделали коммит и поняли, что нужно добавить еще что-то, просто используйтеjj undo.
Ключевые команды JJ для операций
| Задача | Команда |
|---|---|
| Посмотреть историю изменений | jj evolog -p |
| Отменить последнюю операцию | jj undo |
| Повторить после undo | jj redo |
| Просмотреть историю операций | jj op log |
| Восстановить конкретное состояние | jj op restore <operation-id> |
| Сравнить две версии операций | jj op diff --from <a> --to <b> --git |
Часть 2: Управление коммитами и историей
Теперь давайте разберем, как JJ упрощает управление историей коммитов и их описаниями. Начнем с нового проекта:
cd .. && mkdir jj-step-1 && cd jj-step-1 && jj git init
Будем работать над тремя фичами в проекте:
touch file.md
echo "Feat 1" >> file.md
echo "Feature 2" >> file.md
jj commit -m "Feat 1 & 2"
touch file2.md
echo "Feature 3" >> file2.md
jj commit -m "Feat 3"
Screenshot (feat 3)

Погодите, вы понимаете, что везде нужно писать "Feature", а не "Feat" в вашем коде. Так гласят новые правила в компании, вы что пропустили?. Нам надо вернуться и исправить первый коммит. С JJ это будет невероятно просто.
jj edit r
Screenshot (jj edit r)

Обратите внимание, что мы используем только первую букву r вместо полного значения change ID. JJ использует "минимально достаточные" ссылки на коммиты—ровно столько символов, чтобы однозначно идентифицировать ревизию без коллизий в вашем текущем проекте. По мере роста вашего проекта потребуется больше символов.
Теперь мы "внутри" первого коммита. Мы можем изменить file.md как нужно, а потом изменить сообщение коммита с помощью:
Теперь мы "внутри" первого коммита. Мы можем изменить file.md как нужно, а потом изменить сообщение коммита с помощью:
jj describe
Screenshot (jj describe)

Разделение коммитов
Раз уж мы здесь, давайте разделим первый коммит на два отдельных коммита—по одному для каждой фичи. Ну правдо же, не хорошо делать разные задачи в одном коммите. Это также невероятно просто с помощью:
jj split
Нажмите 'F', чтобы развернуть все изменения, выберите "Feature 1" и подтвердите с 'c'. Установите сообщение коммита "Feature 1", сохраните и установите другое сообщение для второго коммита. Теперь у вас должна быть чистая история.Screenshot (jj split)

Screenshot (jj split success)

Вернемся к нашему последнему коммиту с третьей фичей:
jj edit u
И начнем работать над четвертой фичей:
jj new -m "WIP 4 feat"
touch README.md && echo "Blazing fast project" >> README.md
В JJ есть концепция, по которой можно не использовать команду commit. Можно начинать работу с того, что сохраняется старый коммит с описанием и вы начинаете работу над чем то новым с описанием "WIP 4 feat". Потом в любой момент можно переназначить описание коммита и начать новый. Это концепция явно говорит вам, над чем вы начали работу и что вы сейчас делаете.
Погодите—README.md файл, который мы только что добавили, должен быть частью первого коммита. Непорядок! Но никакой проблемы, просто объедините вашу текущую работу с первым коммитом и продолжайте:
jj squash --to r
Screenshot (jj squash)

Отредактируйте сообщение коммита и все готово!
Заключение
Мы попрактиковались с JJ и изучили его мощный и удобный интерфейс для Git. Красота в том, что вы можете использовать его, не изменяя процессы вашей команды—JJ работает поверх обычного Git.
Вы можете поддерживать более чистую историю и намного меньше беспокоиться о том, что AI случайно повредит вашу локальную работу. Уверенность, которую это приносит, бесценна в нашем тревожном мире.
Конечно, я не могу обещать бесшовный переход. Уверенное владение такими инструментами, как JJ, занимает больше времени, и вы можете столкнуться с моментами, когда лучше бы у вас был чистый git. Честно говоря, я принял JJ только со второй попытки использования. Как попробовать первый раз оливки, это может вам не понравиться, но если будете продолжать, то все совсем неплохо.
Я не затронул всё, что может делать JJ, но надеюсь, это было полезно и что вы почувствуете вдохновение попробовать его и сделать вашу работу ещё лучше.
Подписывайтесь
Подписывайтесь на мой канал на https://zatsepin.dev/subscribe, чтобы получить доступ к моему закрытому контенту, исходному коду проектов.