5.2 KiB
Jujutsu: Применение исправлений из stable во все ветки
Да, Jujutsu (jj) отлично справляется с этим workflow и делает его проще, чем в Git, благодаря своей архитектуре. Вот как это работает:
Подход Jujutsu
Jujutsu не требует «переключения веток» в классическом понимании Git, потому что использует модель working-copy-as-commit. Вы можете редактировать любой коммит в репозитории напрямую без checkout.
Workflow в jj
Шаг 1: Во время разработки feature обнаружили баг в stable
Не нужно делать stash или коммитить незавершённую работу. Просто:
# Редактируем коммит в stable напрямую
jj edit <stable-commit-id>
# ИЛИ создаем новый коммит поверх stable
jj new stable
Шаг 2: Делаем исправление
Вносим необходимые изменения (багфикс, оптимизация, рефакторинг). Эти изменения получают уникальный change ID, который сохраняется между ветками.
Шаг 3: Применяем фикс ко всем нужным веткам
Здесь jj раскрывается во всей красе. Два основных подхода:
Вариант A: Rebase-based propagation
# Rebase feature веток на обновлённый stable
jj rebase -b feature-branch -d stable
jj rebase -b another-feature -d stable
Вариант B: Cherry-pick стиль (дублирование + rebase)
# Дублируем change с фиксом и rebase на каждую ветку
jj duplicate <fix-change-id>
jj rebase -r <duplicated-change-id> -d feature-branch
Шаг 4: Селективное применение через revsets
Для исключения deprecated веток используем мощный язык revset в jj:
# Применяем ко всем веткам кроме deprecated
jj rebase -b 'branches() & ~(branches(glob:"deprecated*") | branches("old-feature"))'
Ключевые преимущества jj для этого workflow
- Без загрязнения рабочей директории: Ваше текущее состояние разработки
featureостаётся нетронутым, пока вы работаете над фиксом вstable. - Change IDs отслеживаются между ветками: Одно и то же логическое изменение сохраняет свою идентичность при rebase или дублировании, что упрощает отслеживание применения фикса.
- Автоматическое разрешение конфликтов: При rebase нескольких веток с фиксом
jjпомогает выявлять и разрешать конфликты инкрементально. - Нет "detached HEAD" состояний: В отличие от Git, вы можете свободно навигировать и редактировать любой коммит без риска потерять работу.
Практический пример
# 1. Сейчас работаем над feature
jj log
# 2. Создаём фикс на stable
jj new stable -m "Fix critical bug in validation"
# Вносим изменения
jj commit
# 3. Получаем change ID вашего фикса
FIX_ID=$(jj log -r @ --no-graph -T 'change_id')
# 4. Rebase всех активных feature веток
jj rebase -b 'branches() & ~branches(glob:"deprecated*")' -d stable
# 5. Возвращаемся к работе над feature
jj edit feature
Важные моменты
- Разрешение конфликтов: Если ваш фикс в
stableконфликтует с изменениями вfeature-ветках,jjсоздаст conflict markers, которые нужно будет разрешить для каждой ветки. - Принцип upstream-first: Как и в GitLab Flow, всегда исправляйте сначала в самой upstream-ветке (
stable), затем распространяйте downstream. - Состояние working copy: После операций используйте
jj status, чтобы увидеть, к какому коммиту привязана рабочая копия, иjj edit <branch>для возврата к работе надfeature.
Да,
jjабсолютно поддерживает этот workflow и делает его более эргономичным, чем Git, устраняя накладные расходы на переключение контекста и предоставляя мощные revset-запросы для селективных операций с ветками.