💻 Примеры: жизненный цикл стека

⚡ Кратко: минимальный сценарий

gt init
gt create feat/model   -a -m "feat: model"
gt create feat/api      -a -m "feat: API"
gt log short
gt submit --stack

Пример 1. Инициализация в репозитории

Заходим в обычный Git-репозиторий и включаем Graphite. Он спросит, какая ветка — trunk.

# находимся в учебном репозитории (обычный git-репо)
cd ~/learning_git

gt init
# ? Select a trunk branch: main
# ✓ Graphite initialized. Trunk set to "main".

# авторизация для работы с PR на GitHub
gt auth -t ghp_xxxxxxxxxxxxxxxxxxxx

Пример 2. Собираем стек из трёх веток

Каждая команда gt create кладёт новый «этаж» поверх текущей ветки. Флаг -a застейджит все изменения, -m задаёт сообщение коммита.

# этаж 1 — поверх main
echo "model" > model.txt
gt create feat/tasks-model -a -m "feat: add Task model"

# этаж 2 — поверх feat/tasks-model
echo "service" > service.txt
gt create feat/tasks-service -a -m "feat: add task service"

# этаж 3 — поверх feat/tasks-service
echo "api" > api.txt
gt create feat/tasks-api -a -m "feat: add tasks API"

Смотрим стек целиком:

gt log short
# ◉ feat/tasks-api      (current)
# ◯ feat/tasks-service
# ◯ feat/tasks-model
# ◯ main (trunk)
💡 Читаем сверху вниз: текущая ветка (вершина) — feat/tasks-api, в самом низу — main. Каждая ветка стоит на предыдущей.

Пример 3. Правим низ стека — весь стек обновляется сам

Ревьюер попросил переименовать поле в модели. Спускаемся в самый низ, правим, делаем gt modify — Graphite сам перебазирует service и api на исправленную модель.

gt bottom                 # переключились на feat/tasks-model
# ...правим model.txt...
echo "model v2" > model.txt

gt modify -a              # amend коммита + АВТО-restack веток выше
# ✓ Restacked feat/tasks-service
# ✓ Restacked feat/tasks-api
Вот ради чего всё затевалось. В чистом Git после правки модели пришлось бы вручную: git switch feat/tasks-service && git rebase feat/tasks-model, потом то же для feat/tasks-api. gt modify сделал это одной командой.

Пример 4. Отправляем стек на GitHub

Одна команда пушит все ветки стека и открывает (или обновляет) PR для каждой, корректно проставляя базовую ветку: PR #2 нацелен на ветку PR #1, а не на main.

gt submit --stack         # короткий алиас: gt ss
# ✓ feat/tasks-model   → PR #1 (base: main)
# ✓ feat/tasks-service → PR #2 (base: feat/tasks-model)
# ✓ feat/tasks-api     → PR #3 (base: feat/tasks-service)

Пример 5. Нижний PR влили — синхронизируемся

Коллеги приняли PR #1. Запускаем gt sync: Graphite подтянет свежий main (уже с влитой моделью), перебазирует оставшийся стек и предложит удалить локальную ветку влитого PR.

gt sync
# ✓ Pulled main (1 PR merged)
# ? Delete merged branch feat/tasks-model? (Y/n) Y
# ✓ Restacked feat/tasks-service onto main
# ✓ Restacked feat/tasks-api

Пример 6. Конфликт во время restack

Если при перестроении возникает конфликт слияния, Graphite останавливается — разрешаем как обычно и продолжаем.

gt sync
# CONFLICT in service.txt
# ...правим конфликт в редакторе...
git add service.txt
gt continue               # продолжить прерванную операцию
# или: gt abort — откатить всё к состоянию до операции
⚠️ Проверить по документации. Точный текст вывода и набор флагов зависят от версии Graphite. Здесь вывод приведён схематично для понимания логики — сверяйтесь с gt --help.