Проблема большого pull request
Представьте задачу «добавить раздел задач (Tasks) в приложение». По-честному в ней несколько слоёв: модель базы данных, слой бизнес-логики, REST-эндпоинты, тесты. Если всё это сложить в одну ветку и один pull request, получится дифф на сотни строк. Ревьюеру тяжело: непонятно, с чего начать, легко пропустить ошибку, обсуждение растягивается на дни, а ветка тем временем устаревает относительно main.
Подход stacked PRs решает это так: каждый логический слой — отдельная маленькая ветка и отдельный небольшой PR, и эти ветки выстроены в стек — цепочку, где каждая следующая ответвляется от предыдущей.
Каждый PR маленький и ревьюится независимо. PR #1 можно влить, как только он готов, не дожидаясь остальных.
feat/tasks-model (низ стека), все ветки выше «висят» на старом коммите и их нужно перебазировать вручную — git rebase за git rebase. На стеке из 4–5 веток это утомительно и легко ошибиться. Именно это автоматизирует Graphite.
Модель Graphite
gt (Graphite CLI) — это надстройка поверх Git. Она не заменяет Git и не меняет формат репозитория: ветки и коммиты остаются обычными, команды git продолжают работать. Graphite лишь хранит дополнительные метаданные — кто чей родитель в стеке.
trunk (ствол)
trunk — это ваша основная ветка, обычно main или master. От неё растут все стеки. Вы задаёте её один раз командой gt init, и Graphite запоминает.
Родитель и потомок
Каждая ветка в стеке знает свою родительскую ветку (ту, от которой ответвилась) и своих потомков (те, что ответвились от неё). Это и есть «стек»: цепочка родитель → потомок от trunk до вершины.
restack — сердце Graphite
restack — это перестроение стека: Graphite проходит по цепочке и перебазирует (git rebase) каждую ветку на актуальную вершину её родителя. Вы делаете это явно командой gt restack — или оно случается автоматически после gt modify, когда вы поправили нижнюю ветку.
gt modify -a — и все ветки выше сами перебазировались на исправленную версию. В чистом Git это была бы серия ручных rebase.
Базовый цикл работы
- Создание.
gt createсоздаёт новую ветку поверх текущей и коммитит изменения — то есть кладёт новый «этаж» на стек. - Изменение.
gt modifyправит коммит текущей ветки и автоматически перестраивает ветки выше. - Навигация.
gt up/gt downдвигают вас по этажам стека вместоgit switchс длинными именами. - Отправка.
gt submit --stackпушит все ветки стека и создаёт/обновляет pull request для каждой. - Синхронизация.
gt syncподтягивает свежийmain, перебазирует стек и предлагает удалить ветки уже влитых PR.
Graphite и чистый Git
Полезно держать в голове, что каждая команда gt — это знакомые операции Git под капотом:
| Graphite | Что делает в терминах Git |
|---|---|
gt create -a -m | новая ветка + git add + git commit + запись родителя |
gt modify -a | git commit --amend + rebase веток выше |
gt restack | серия git rebase по цепочке родителей |
gt submit --stack | git push --force-with-lease + открытие PR |
gt sync | git fetch + rebase + чистка влитых веток |
gt submit делает force-push ваших веток. Для личных feature-веток стека это нормально. Но main в стек включать нельзя — иначе вы перепишете общую историю команды.
gt --help и graphite.com/docs.