Агент-инженер по репозиторию · Модуль 4 · Урок 4.4

Чекпойнт-коммиты и откат: обратимость

Зачем (какую проблему чиним)

Агент сделал серию правок, прогнал тесты — часть стало хуже. Если всё лежит одной кучей незакоммиченных изменений, откатить только неудачный шаг нельзя: либо теряем всё, либо тащим поломку дальше. Нужны чекпойнт-коммиты после каждого успешного шага и умение откатываться к последнему хорошему.

Решение и альтернативы

Решение: после каждого шага плана, прошедшего проверки, агент делает чекпойнт-коммит в своей ветке (git commit в worktree) с осмысленным сообщением. Если следующий шаг сломал сборку и почини́ть не удаётся — откат к последнему чекпойнту (git reset --hard <checkpoint> в worktree, не трогая основной репозиторий). История ветки агента — это лента обратимых точек.

Альтернативы: один коммит в конце — нечего откатывать пошагово; git revert — корректно для публичной истории, но внутри одноразовой ветки агента reset к чекпойнту проще и чище (ветку всё равно причёсываем перед MR).

DIFF

Добавляем чекпойнт-коммит и откат к последнему чекпойнту — строго в worktree, через assertWritable.

⚠ Безопасность

Обратимость — это безопасность: каждый чекпойнт даёт точку, к которой гарантированно можно вернуться, и фиксируется в аудит-логе (версия v5). reset --hard выполняется только в worktree агента — основной репозиторий и main недостижимы. Чекпойнты не пушатся автоматически: публикация — отдельное решение (версия v4, MR).

Проверка

Сценарий: шаг 1 ок (чекпойнт), шаг 2 ломает сборку → агент откатывается к чекпойнту шага 1 и пробует иначе. git -C <wt> log --oneline показывает ленту чекпойнтов; основной репозиторий не затронут.

Глубже

Durable-исполнение, идемпотентность, восстановление после сбоя — курс «Продакшн-разработка», Модуль 1 (гл. 1). Полный аудит обратимых действий — версия v5 (урок 6.4).

checkpoint.go: чекпойнт-коммит и откат в worktree (новый файл, фрагмент)
+// checkpoint фиксирует успешный шаг отдельным коммитом в ветке агента.
+func (w *Workspace) checkpoint(ctx context.Context, msg string) (string, error) {
+	if err := w.assertWritable(ctx); err != nil {
+		return "", err
+	}
+	if _, err := runGitWrite(ctx, w.Dir, "add", "-A"); err != nil {
+		return "", err
+	}
+	if _, err := runGitWrite(ctx, w.Dir, "commit", "-m", msg); err != nil {
+		return "", err
+	}
+	return runGitWrite(ctx, w.Dir, "rev-parse", "HEAD") // sha чекпойнта в аудит
+}
+
+// rollbackTo откатывает worktree к чекпойнту. Только в worktree агента —
+// основной репозиторий и main недостижимы.
+func (w *Workspace) rollbackTo(ctx context.Context, sha string) error {
+	if err := w.assertWritable(ctx); err != nil {
+		return err
+	}
+	_, err := runGitWrite(ctx, w.Dir, "reset", "--hard", sha)
+	return err
+}

Anti-patterns

Грабли обратимости
ГрабляПочему плохоКак правильно
Копить все правки одной кучей и коммитить в концеНельзя откатить только неудачный шаг — теряешь всё или тащишь поломкуЧекпойнт-коммит после каждого успешного шага; откат к последнему хорошему
reset --hard в основном репозиторииМожно уничтожить чужую работу/состояние вне изоляцииОткат строго в worktree агента; основной репозиторий не трогаем
Автопуш чекпойнтовСырые промежуточные коммиты утекают наружу до ревьюЧекпойнты локальны; публикация — отдельное решение на версии MR

Практическое задание (RA-v3)

  • Добавить checkpoint (коммит шага) и rollbackTo (reset к sha) строго в worktree.
  • Записывать sha чекпойнтов для будущего аудита; не пушить автоматически.
  • Закоммитить: git commit -m "v3: checkpoint commits and rollback".

Проверка знаний

Агент сделал 4 правки без промежуточных коммитов; последняя сломала сборку.

Почему чекпойнт-коммиты после каждого успешного шага лучше?

  • A Они ускоряют тесты
  • B Дают точки обратимости: можно откатить только неудачный шаг к последнему зелёному чекпойнту, не теряя хорошие правки
  • C Уменьшают размер репозитория
  • D Git этого требует