Перейти к основному содержанию Перейти к навигации Перейти к нижнему колонтитулу
Ограниченное время: Программа Design Partner. План BUSINESS бесплатно на всю жизнь.

Ветвление в стиле Git

Используйте форки с копированием при записи как коммиты git: заморозьте форк в неизменяемый коммит, назовите ветви, восстановите коммиты в перезаписываемые форки, просматривайте историю и выполняйте слияние без изменения живого репозитория.

Ветвление в стиле Git

Основная идея: Rediacc преобразует форки с копированием при записи в версионирование в стиле git. Каждый неизменяемый форк является коммитом: побайтово стабильным, замороженным образом, который отказывается монтироваться. Ветви являются именованными ссылками, указывающими на коммит. rdc repo checkout клонирует коммит через reflink обратно в перезаписываемый рабочий форк, а rdc repo merge объединяет две линии истории без изменения живого репозитория на месте.

Модель основана на двух хранилищах. Машина является хранилищем объектов: коммиты являются неизменяемыми образами форков, живущими в хранилище данных. Конфигурация CLI является хранилищем ссылок: имена ветвей, текущий HEAD и журнал ссылок хранятся в вашей локальной конфигурации, а не на машине. Это то же разделение, которое git использует между .git/objects и .git/refs.

Когда использовать

Обращайтесь к ветвлению, когда форк заслужил имя. Агент AI поработал в форке production, результат выглядит хорошо, и вы хотите замороженную, именованную контрольную точку, к которой можно вернуться или которую можно продвинуть позже: rdc repo commit замораживает её, rdc repo branch её именует. Перед рискованной миграцией зафиксируйте рабочий форк, чтобы у вас была точная точка отката, гарантированно не изменяющаяся (неизменяемый коммит отказывается монтироваться, поэтому ничто не может в него записывать). Для сравнения двух контрольных точек rdc repo diff работает между любыми двумя коммитами, поскольку они имеют общего предка с копированием при записи. Чтобы перенести проверенную линию работы обратно в целевой форк, rdc repo merge строит результат в клоне через reflink и атомарно подменяет его, поэтому запущенный целевой форк никогда не будет повреждён в процессе слияния.

Не используйте это вместо rdc repo fork, когда вам нужна только одноразовая копия. Простой форк является правильной единицей для эфемерной, поресурсной изоляции. Коммиты добавляют ценность, когда состояние стоит сохранить, назвать или отправить.

Связь коммитов и форков

Репозиторий является одним файлом образа LUKS на пуле btrfs. Форк является reflink-клоном этого образа с постоянным временем, поэтому форк репозитория размером 1 ГБ и репозитория размером 100 ГБ стоит одинаково. Коммит является форком, помеченным как неизменяемый: renet отказывается его монтировать, что сохраняет его образ побайтово стабильным навсегда. Эта побайтовая стабильность делает коммит надёжной точкой отката и детерминированной базой для перекрёстной машинной дельта-передачи.

rdc repo commit записывает сообщение коммита, автора, временную метку и родительский коммит внутри тома (поэтому метаданные путешествуют вместе с образом при push) и также зеркалирует их вне тома (чтобы rdc repo log мог обходить историю без разблокировки чего-либо). Рабочий форк, который вы зафиксировали, продолжает без изменений, точно так же как git оставляет ваше рабочее дерево нетронутым после коммита.

Команды

rdc repo commit

Заморозить смонтированный рабочий форк в новый неизменяемый коммит.

rdc repo commit --name <fork> --message "<message>" -m <machine>
ПараметрОписаниеПо умолчанию
--name <name>Рабочий форк для фиксации. Должен быть смонтирован. Обязательно.обязательно
--message <msg>Сообщение коммита. Обязательно.обязательно
--author <author>Автор коммита, записываемый в метаданных коммита.не задано
-m, --machine <name>Целевая машина. Обязательно.обязательно
--debugПодробная диагностика в stderr.выкл

Новый коммит регистрируется в локальной конфигурации с immutable: true, а headCommit рабочего форка продвигается, чтобы указывать на него. Фиксация неизменяемого репозитория отклоняется: сначала извлеките его в перезаписываемый форк.

rdc repo branch

Создать именованную ссылку ветви, указывающую на текущий коммит рабочего форка.

rdc repo branch --branch <name> --name <fork>
ПараметрОписаниеПо умолчанию
--branch <branch>Имя новой ветви. Обязательно.обязательно
--name <name>Рабочий форк, чей текущий коммит будет указывать ветвь. Обязательно.обязательно

Это операция только с конфигурацией. На машине ничего не происходит. Ссылка ветви сопоставляет имя с headCommit рабочего форка, поэтому у форка должен быть хотя бы один коммит.

rdc repo checkout

Клонировать неизменяемый коммит (или верхушку ветви) через reflink в свежий перезаписываемый рабочий форк.

rdc repo checkout --ref <commit> --tag <newFork> -m <machine>
rdc repo checkout --ref <branchName> --from <fork> --tag <newFork> -m <machine>
ПараметрОписаниеПо умолчанию
--ref <commit|branch>GUID коммита для извлечения или имя ветви, когда задан --from. Обязательно.обязательно
--tag <name>Имя для нового перезаписываемого рабочего форка. Обязательно.обязательно
-m, --machine <name>Целевая машина. Обязательно.обязательно
--from <workingFork>Разрешить --ref как имя ветви в наборе ветвей этого рабочего форка.прямой коммит
--debugПодробная диагностика в stderr.выкл
--skip-router-restartПропустить шаг перезапуска маршрутизатора.выкл

Извлечение повторно использует путь reflink форка, поэтому оно почти мгновенно и имеет постоянное время независимо от размера репозитория. headCommit нового рабочего форка устанавливается на извлечённый коммит.

rdc repo log

Обходить историю коммитов, достижимую из рабочего форка или коммита.

rdc repo log --name <fork> -m <machine>
ПараметрОписаниеПо умолчанию
--name <name>Рабочий форк или коммит, с которого начинается обход истории. Обязательно.обязательно
-m, --machine <name>Целевая машина. Обязательно.обязательно
--jsonВывести историю коммитов в формате JSON.выкл
--debugПодробная диагностика в stderr.выкл

log обходит цепочку родителей, записанную rdc repo commit, читая внешнее зеркало состояния, поэтому никакой коммит не разблокируется и не монтируется. Только для чтения.

rdc repo merge

Объединить исходный коммит или форк в целевой рабочий форк без изменения живого целевого форка на месте.

rdc repo merge --name <target> --from <source> -m <machine>
rdc repo merge --name <target> --from <source> --resolve theirs -m <machine>
ПараметрОписаниеПо умолчанию
--name <name>Целевой рабочий форк для слияния. Обязательно.обязательно
--from <source>Исходный коммит или форк для слияния. Обязательно.обязательно
-m, --machine <name>Целевая машина. Обязательно.обязательно
--forceСначала остановить смонтированный или запущенный целевой форк, затем выполнить слияние. Никогда не изменяет живое монтирование.выкл
--resolve <ours|theirs>Трёхстороннее слияние на уровне файлов: применить поофайловые изменения источника к цели, оставляя (ours) или принимая (theirs) версию источника для файлов, изменённых с обеих сторон. Не указывайте для полного принятия источника.выкл
--base <guid>Коммит общего предка для трёхстороннего слияния (используется с --resolve). По умолчанию родительский коммит исходного коммита или текущий коммит цели.авто
--debugПодробная диагностика в stderr.выкл

Результат строится в клоне через reflink и атомарно подменяется за crash-safe маркером, поэтому прерванное слияние оставляет исходный целевой форк нетронутым. Смонтированный или запущенный целевой форк отклоняется, если не задан --force, который чисто останавливает цель перед подменой.

Без --resolve слияние является полным принятием источника (цель становится источником). С --resolve это трёхстороннее слияние на уровне файлов относительно записанного родителя исходного коммита: файлы, изменённые только с одной стороны, берутся с этой стороны, а файлы, изменённые с обеих сторон, разрешаются флагом. Конфликтующие пути выводятся.

rdc repo gc

Сборка мусора из неизменяемых объектов коммитов на машине, которые не достигаются никакой ветвью или HEAD.

rdc repo gc -m <machine>            # предварительный просмотр (по умолчанию)
rdc repo gc --apply -m <machine>    # удалить недостижимые коммиты
ПараметрОписаниеПо умолчанию
-m, --machine <name>Машина для сборки мусора. Обязательно.обязательно
--applyФактически удалить недостижимые коммиты (иначе предварительный просмотр).выкл
--debugПодробная диагностика в stderr.выкл

Достижимость вычисляется из локальной конфигурации (хранилища ссылок): набор коммитов, достижимых при следовании каждой верхушки ветви и HEAD вниз по цепочке родителей. Неизменяемые коммиты на машине вне этого набора недостижимы. Смонтированный объект или рабочий форк никогда не собирается.

rdc repo fsck

Проверить соответствие ссылок конфигурации объектам, присутствующим на машине.

rdc repo fsck -m <machine>
ПараметрОписаниеПо умолчанию
-m, --machine <name>Машина для проверки. Обязательно.обязательно

Сообщает о висячих ссылках (верхушка ветви или HEAD, указывающие на GUID без объекта на машине) и осиротевших коммитах (неизменяемый коммит на машине, которого не достигает ни одна ссылка). Только для чтения; освободите осиротевшие объекты с помощью rdc repo gc --apply.

Неизменяемые форки

rdc repo fork --immutable помечает новый форк как доступный только для чтения при создании, создавая базу, эквивалентную коммиту, без отдельного шага commit.

rdc repo fork --parent <name> --tag <tag> --immutable -m <machine>

Неизменяемый форк отказывается монтироваться, что сохраняет его образ побайтово стабильным навсегда. Это полезно как замороженная база для кросс-машинной дельта-передачи, где база должна быть идентичной на обоих концах. Чтобы вносить изменения, извлеките его (или снова разветвите) в перезаписываемую копию.

Примеры

Зафиксировать рабочий форк

$ rdc repo commit --name myapp:work --message "schema migration applied" -m server-1
Committed 4f3c2a1b9d8e: schema migration applied

Зафиксировать с явным автором

$ rdc repo commit --name myapp:work --message "nightly snapshot" --author ci-bot -m server-1
Committed 7a1b2c3d4e5f: nightly snapshot

Назвать ветвь в текущем коммите

$ rdc repo branch --branch staging --name myapp:work
Branch "staging" -> 4f3c2a1b9d8e

Извлечь коммит в свежий перезаписываемый форк

$ rdc repo checkout --ref 4f3c2a1b9d8e --tag rollback-test -m server-1

Извлечь верхушку ветви по имени

С --from значение --ref разрешается как имя ветви на заданном рабочем форке:

$ rdc repo checkout --ref staging --from myapp:work --tag staging-copy -m server-1

Обход истории

$ rdc repo log --name myapp:work -m server-1
commit 4f3c2a1b9d8e
  Author: ci-bot  Date: 2026-05-29T10:14:02Z
  schema migration applied
commit 9d8e7a1b2c3d
  Author: ci-bot  Date: 2026-05-28T22:01:55Z
  initial import

История в формате JSON

--json выдаёт структурированный обход, сначала новые:

$ rdc repo log --name myapp:work --json -m server-1
{
  "success": true,
  "start": "4f3c2a1b9d8e",
  "entries": [
    {
      "guid": "4f3c2a1b9d8e",
      "message": "schema migration applied",
      "author": "ci-bot",
      "parent": "9d8e7a1b2c3d",
      "committed_at": "2026-05-29T10:14:02Z",
      "immutable": true
    }
  ]
}

Сравнение двух коммитов

rdc repo diff работает между любыми двумя коммитами, поскольку они имеют общего предка с копированием при записи. Извлеките один коммит, затем сравните его с другим:

$ rdc repo checkout --ref 4f3c2a1b9d8e --tag review -m server-1
$ rdc repo diff --name review --base myapp:work -m server-1
M  db/schema.sql

1 file changed: 0 added, 1 modified, 0 deleted, 0 renamed

См. rdc repo diff для полного справочника diff.

Слияние проверенной линии обратно

$ rdc repo merge --name myapp:main --from myapp:work -m server-1
Merged myapp:work into myapp:main

Слияние в запущенный целевой форк

Смонтированный или запущенный целевой форк отклоняется, если не задан --force, который сначала останавливает его:

$ rdc repo merge --name myapp:main --from myapp:work --force -m server-1
Merged myapp:work into myapp:main

Трёхстороннее слияние на уровне файлов

Два форка (feature и hotfix), извлечённые из одного коммита, каждый изменил некоторые файлы. --resolve theirs применяет источник (hotfix) к цели (feature): файлы, изменённые только с одной стороны, берутся с этой стороны, а файлы, изменённые с обеих сторон, разрешаются в пользу источника. База определяется автоматически из общего предка (или укажите её с --base):

$ rdc repo merge --name myapp:feature --from myapp:hotfix --resolve theirs -m server-1
Merged myapp:hotfix into myapp:feature (three-way); 1 conflict(s) resolved --theirs: [config/app.yaml]

config/app.yaml изменился с обеих сторон и был разрешён в пользу источника; файл, добавленный только в hotfix, применяется, а файл, изменённый только в feature, сохраняется. Конфликтующие пути выводятся для проверки.

Создание неизменяемой базы напрямую

$ rdc repo fork --parent myapp --tag baseline-v1 --immutable -m server-1

Дельта-передача push и pull

Неизменяемый побайтово стабильный образ также является основой для блочной дельта-передачи. Когда одна и та же неизменяемая база существует на двух машинах, push или pull может вычислить изменённые блоки относительно этой базы и передать только их, вместо сканирования всего зашифрованного образа. Репозиторий размером 1 ГБ с несколькими изменёнными блоками тогда передаётся в мегабайтах.

Обычно вам не нужно передавать базу вручную. После полного push CLI сохраняет отправленный образ как неизменяемую базу на обеих машинах и записывает её, поэтому следующий push этого репозитория автоматически отправляет только дельту, без флага, даже для форка, который уже существует на цели. (Полный повторный push существующего форка всё ещё требует --force, так как он заменяет весь образ вместо применения проверенной дельты.) Передайте --delta-base <guid> для указания конкретной базы и --strategy <auto|physical|shared> для контроля того, как обнаруживаются изменённые блоки (auto правильно в почти всех случаях).

# Первый push является полной передачей; он также сохраняет повторно используемую базу на обоих концах.
$ rdc repo push --name myapp:work --to-machine backup-1 -m server-1

# После локальных изменений следующий push отправляет только изменённые блоки, без флага.
$ rdc repo push --name myapp:work --to-machine backup-1 -m server-1

# Указать явную базу (неизменяемый коммит, присутствующий на обеих машинах).
$ rdc repo push --name myapp:work --to-machine backup-1 --delta-base 4f3c2a1b9d8e -m server-1

# Дельта также работает в обратном направлении, извлекая только изменённые блоки из машины-источника.
$ rdc repo pull --name myapp:work --from-machine backup-1 --delta-base 4f3c2a1b9d8e -m server-1

# Повторное извлечение существующего локального репозитория (перезапись) с --force.
$ rdc repo pull --name myapp:work --from-machine backup-1 --force -m server-1

Дельта-передача применяется только между машинами (удалённый с базой FIEMAP). Push в облачное объектное хранилище всегда передаёт полный образ. База должна быть побайтово идентичной на обоих концах, что именно гарантирует неизменяемый коммит или форк с --immutable.

Схема JSON

rdc repo log --json оборачивает результат renet в стандартный конверт. Обойдённая история находится в entries, сначала новые:

ПолеТипОписание
successbooleanЗавершился ли обход.
startstringGUID, с которого начался обход.
entriesarrayОдин объект на коммит, сначала новые.
entries[].guidstringGUID коммита.
entries[].messagestringСообщение коммита. Отсутствует, если пустое.
entries[].authorstringАвтор коммита. Отсутствует, если пустой.
entries[].parentstringGUID родительского коммита. Отсутствует у корня.
entries[].committed_atstringВременная метка коммита в формате RFC 3339. Отсутствует, если не задана.
entries[].immutablebooleanПомечен ли коммит как доступный только для чтения (всегда true для настоящего коммита).

Для полей конверта и правил автоопределения, которые выдают JSON в средах не-TTY, см. Справочник JSON-вывода.

Ограничения

  • Ссылки являются локальными. Имена ветвей, HEAD и журнал ссылок хранятся в вашей конфигурации CLI, а не на машине. Push коммита на другую машину отправляет объект коммита и его метаданные внутри тома, но ссылка ветви является концепцией на стороне конфигурации.
  • Коммит отказывается монтироваться. Это и есть суть: неизменяемость делает коммит побайтово стабильным. Чтобы запустить или изменить коммит, сначала извлеките его в перезаписываемый рабочий форк.
  • Разрешение слияния выполняется на уровне файлов, а не строк. Поддерживаются как полное принятие источника (без --resolve), так и трёхстороннее слияние на уровне файлов (--resolve ours|theirs). Трёхстороннее слияние разрешает конфликты целым файлом за раз согласно флагу; оно не создаёт фрагменты на уровне строк или маркеры слияния внутри файла.
  • История является цепочкой родителей. rdc repo log обходит единственную ссылку parent, записанную во время коммита. Он останавливается, когда достигает коммита, метаданные которого отсутствуют на запрашиваемой машине.

Смотрите также

  • rdc repo diff. Сравнение на уровне файлов между любыми двумя связанными коммитами или форками.
  • Репозитории. Создание, разветвление, монтирование и работа с репозиториями.