Документация
История проекта
Локальные снимки проекта, совместимые с Git, структурные различия, проверяемые ветки и дополнительное зеркалирование GitHub.
Автоматически переведено с английского. Смотреть оригинал на английском
Рабочая копия и история
Записи SQLite приложения являются текущей рабочей копией проекта. @cadcamfun/vcs хранит Git-совместимые объекты, деревья, коммиты и ссылки через внедренный объектный бэкэнд; сайдкар сохраняет этот бэкэнд в SQLite. Операции с историей работают локально без исполняемого файла Git или учетной записи GitHub.
Коммит делает снимок проекта и связанных с ним ресурсов проектирования/производства. Ветки указывают на коммиты, а HEAD идентифицирует извлеченную ветку. Таблицы версий ресурсов сосуществуют с этой историей уровня проекта; версия чертежа и фиксация проекта имеют разные области действия.
Рабочий процесс фиксации и ветвления
- Читать
GET /api/projects/:id/vcs/statusчтобы увидеть текущую ветку HEAD и измененные пути. - Создайте ветку с
POST /vcs/branches, затем проверьте это с помощьюPOST /vcs/checkout. Пути ветвей здесь указаны относительно префикса API проекта. - Отредактируйте ресурсы проекта и зафиксируйте их с помощью
POST /vcs/commitи непустое сообщение. - Осмотреть
GET /vcs/logиGET /vcs/diff. Журнал поддерживает версию, ограничение и дополнительный отслеживаемый путь. - Откройте запрос на включение проекта, просмотрите его структурные изменения и выполните слияние после разрешения блокирующих проверок или конфликтов.
Извлечение, восстановление и операции, перемещающие рабочую ветвь, отказываются от грязной рабочей копии там, где это необходимо. При восстановлении записывается новая фиксация, представляющая более ранний контент, при необходимости ограниченная выбранными путями. Он сохраняет последующую историю, а не переписывает ее.
Содержимое снимка
project.json
drawings/<id>.json
components/<id>.json
toolpaths/<id>.json
materials/<id>.json
tools/<id>.json
machine-configs/<id>.json
costs/<id>.json
.cadcamfun/workflows/<name>.yml Один файл JSON для каждой сущности хранит несвязанные изменения отдельно. Снимок включает элементы библиотеки, на которые ссылаются траектории движения инструмента и сметы производственных затрат, поэтому восстановленные производственные данные могут сохранить свои зависимости. Идентификаторы объектов, используемые в качестве имен файлов, ограничены безопасными буквами, цифрами, символами подчеркивания и дефисами, но не более 128 символов.
Ключи JSON сортируются рекурсивно, а файлы используют стабильную красивую печать с последней новой строкой. Массивы сохраняют свой порядок. Дополнительные текстовые файлы могут перемещаться вместе со снимком уровня пакета; конечная точка общедоступной фиксации принимает дополнительные файлы только под .cadcamfun/workflows/ с безопасным именем файла YAML.
Объекты используют формат свободных объектов git байт за байтом, поэтому идентификаторы объектов совпадают с вычисленными git. Записи дерева представляют собой либо файлы (режим 100644) или каталоги (режим 40000). Подпись коммита записывает имя, адрес электронной почты, время в Unix-секундах и +hhmm/-hhmm компенсировать. Филиалы хранятся под refs/heads/, а ветка проекта по умолчанию — main (packages/vcs/src/object.ts, repository.ts).
Семантика различий и слияний
Репозиторий вычисляет базу слияния, напрямую обрабатывает неизмененные стороны и выполняет структурные трехсторонние слияния для измененного JSON. Независимые изменения свойств объекта могут объединяться без конфликтов. О параллельных несовместимых изменениях одного и того же скаляра или массива сообщается через указатели JSON; массивы не объединяются поэлементно.
Различия между объектами включают путь, тип ресурса, идентификатор и имя, если они доступны, статус добавления/изменения/удаления, а также изменения свойств со значениями до/после. В файлах, отличных от JSON, используется конфликтное поведение на уровне файла. Слияние репозитория с конфликтами возвращает их пути и указатели без написания объединенного коммита.
Запросы на извлечение и разрешения
Запросы на включение проекта доступны по адресу /api/projects/:id/pulls. При открытии одного из них записываются название, тело, глава, основа и тип автора. Подробные ответы включают запрос на включение, обзоры и изменения. Поддержка отзывов comment, approve, и request-changes, с необязательным путем и указателем свойства.
Последний вердикт об отсутствии комментариев для каждого рецензента управляет блоком запросов на изменения. В слиянии отказано, пока любые такие запросы вердикта изменяются. Реализация не требует положительного одобрения, если нет решения о блокировке. В объединенных различиях пул-реквестов используется записанная фиксация слияния, поэтому последующее перемещение ветки не меняет эту запись проверки.
Чтение истории, фиксация, ветвление, открытие запросов на включение и просмотр требуют доступа к проекту. Для перемещения рабочей копии и обслуживания общей ветки требуется владелец или администратор/менеджер организации, как это предусмотрено обработчиком. Грязные или конфликтующие операции возвращают 409; защищенные действия возвращают 403; отсутствующие ссылки или ресурсы возвращают 404; другие недопустимые операции возвращают 400.
Актор ИИ не может фиксировать, восстанавливать или объединять в main. Ассистент использует ветку предложения и открывает запрос на включение, чтобы человек мог его просмотреть. Записи аудита и уведомлений идентифицируют изменения, внесенные помощником.
Дополнительное зеркало GitHub
GET и PUT /api/projects/:id/vcs/remote прочтите или установите owner/repo зеркало GitHub; null отключает его. Нажмите и потяните использование POST /vcs/push и /vcs/pull, с токеном GitHub пользователя в x-github-token за этот звонок.
Push передает доступные объекты и обновляет удаленную ветку, не перезаписывая невыполненные удаленные фиксации. Pull извлекает удаленную ветку и объединяет ее локально, отказываясь от грязной рабочей копии. Дивергентные несовместимые изменения JSON возвращают конфликты, а не молча заменяют локальный контент.
Сопутствующий транспорт использует операции объекта/ссылки GitHub REST. Токен GitHub предоставляется для каждого запроса и не сохраняется как данные проекта. Локальный запрос на включение — это запись проверки приложения; это не автоматический запрос на извлечение GitHub.
Снимки и восстановление
snapshotToFiles преобразует снимок проекта в каноническое содержимое файла; filesToSnapshot восстанавливает списки доменов. ProjectVcsRepo считывает текущие ресурсы базы данных и применяет восстановленные снимки. Восстановление всего проекта может изменить несколько связанных таблиц, поэтому просмотрите их различия и очистите рабочую копию перед переключением истории.
Транспортные и объектные API
Пакет VCS экспортирует кодирование и чтение объектов, Repository, адаптеры хранилища, канонический JSON и помощники слияния, преобразование снимков, различия сущностей, синхронизация GitHub и транспортные интерфейсы. Тесты могут внедрить в память серверную часть объекта или поддельный транспорт вместо доступа к репозиторию пользователя.
Точки входа в реализацию
packages/vcs/src/repository.ts владеет коммитами, ссылками, обходом, восстановлением и слиянием; json.ts владеет структурными слияниями; snapshot.ts определяет отслеживаемые ресурсы; diff.ts описывает изменения сущности; github.ts и transport.ts реализовать зеркалирование. Сайдкар project-vcs.ts добавляет политику и настойчивость актера, в то время как http/vcs.ts обеспечивает разрешение на транспорт и мероприятия.
История операций и автоматизация
Определения рабочих процессов проверяются вместе с проектом и запускаются на основе зафиксированных файлов. Фиксация может инициировать эти рабочие процессы после записи истории; неудачный рабочий процесс не отменяет фиксацию. При диагностике состояния проекта сохраняйте отдельные сохранения локальных ресурсов, фиксации проекта, результаты рабочего процесса и удаленную синхронизацию.
Попробуйте репозиторий без данных приложения
Соединение хранилища объектов позволяет выполнять интеграцию целиком и разветвляться в памяти. Запустите это внутри рабочей области, которая зависит от @cadcamfun/vcs, такой как apps/sidecar. Он не затрагивает базу данных проекта рабочего стола.
import { Repository, memoryBackend, canonicalJson } from "@cadcamfun/vcs"
const repo = new Repository(memoryBackend())
const author = { name: "Workshop", email: "workshop@example.invalid", time: 0, tz: "+0000" }
repo.commit({ "project.json": canonicalJson({ name: "Blank", revision: 1 }) }, {
message: "Initial blank", author
})
repo.createBranch("proposal/wider-blank")
repo.checkout("proposal/wider-blank")
repo.commit({ "project.json": canonicalJson({ name: "Blank", revision: 2 }) }, {
message: "Record revised blank", author
})
console.log(repo.currentBranch()) // proposal/wider-blank
console.log(repo.log().length) // 2 Repository.commit получает полное дерево файлов для этого коммита, а не патч. Sidecar строит это дерево из рабочих записей базы данных и переносимых текстовых файлов. Интеграция на уровне пакета должна сохранять файлы, которые она намеревается сохранить. В примере в памяти не применяется политика владения сайдкаром или политика субъектов ИИ; они реализуются службой проекта и уровнем HTTP.
Источник: packages/vcs/src/store.ts, repository.ts, и apps/sidecar/src/services/project-vcs.ts.
Целенаправленный просмотр, восстановление и синхронизация
Записывайте изменения в рабочей копии перед переключением ветвей. Для новой ветки требуется разрешимая фиксация исходного кода, поэтому перед разветвлением инициализируйте незафиксированный проект с помощью первой фиксации. Создание ветки создает только ссылку; checkout — это отдельная операция, которая применяет свой снимок к рабочей базе данных.
Для запроса на включение сравните заголовок с его базой слияния и просмотрите различия на уровне свойств. Более поздний комментарий не отменяет предыдущий вердикт о запросе на изменение: рецензент должен представить последующий вердикт об утверждении. Объединенный PR может выполнить ускоренную перемотку вперед или создать коммит слияния в соответствии с происхождением репозитория; проверьте записанную фиксацию слияния вместо того, чтобы предполагать фиксированное количество родителей.
При слиянии с выданной базой сервис требует чистую рабочую копию и применяет новый снимок базы. Когда извлекается другая ветка, слияние базы PR обновляет ссылку этой ветки без замены текущей рабочей базы данных. Последующая проверка загружает обновленную базу.
Нажмите и потяните синхронизировать историю зафиксированных событий. Несохраненное содержимое пользовательского интерфейса и незафиксированное состояние базы данных не являются удаленными снимками. Удаленное отклонение — это запрос на выборку/слияние в первую очередь; это не инструкция по перезаписи удаленной ветки.
Источник: packages/vcs/src/repository.ts, github.ts, и apps/sidecar/src/services/project-vcs.ts.
Восстановление после сбоев истории
| Отказ | Следующее действие |
|---|---|
NothingToCommit | Сравните рабочие файлы базы данных с помощью HEAD. Повторное сохранение тех же значений ресурсов не приводит к созданию другого дерева. |
| Неверная или существующая ветка | Выберите новое безопасное имя ссылки. Имена не могут содержать обходные черты, двойные косые черты, фрагменты ссылочных выражений или конечную косую черту/суффикс .lock. |
| Незафиксированные изменения | Зафиксируйте или намеренно восстановите/удалит намеченные ресурсы перед извлечением, извлечением или операцией защищенного рабочего копирования. |
| Объединить конфликт с путем/указателями | Проверьте эти свойства в истории базы/головы, создайте проверенное решение и повторите попытку. Неудачное слияние репозитория не привело к частичной фиксации слияния. |
| Рецензент запросил изменения | Разрешите отзыв и получите обновленный вердикт от этого рецензента без комментариев. |
| Актеры ИИ не могут действовать на главном | Используйте ветку предложения AI и запрос на включение, проверенный человеком. Изменение флага подтверждения не снимает ограничение субъекта. |
Источник: packages/vcs/src/repository.ts, apps/sidecar/src/services/project-vcs.ts, и http/vcs.ts. Справочник по API перечисляет фактические схемы запросов и ответов.
Схема репозитория
Проект хранится в репозитории как один файл JSON для каждой сущности. Таким образом, редактирование чертежа никогда не затрагивает файл траектории, и макет естественным образом читается на GitHub. snapshotToFiles записывает этот макет из ProjectSnapshot, и filesToSnapshot читает его обратно.
| Список снимков | Каталог | Содержание |
|---|---|---|
project | project.json | Метаданные проекта. |
drawings, components, toolpaths | те же имена | Проектные и производственные предприятия. |
materials, tools, machineConfigs | materials/, tools/, machine-configs/ | Элементы библиотеки, на которые ссылаются траектории, имеют версию проекта, поэтому восстановленная траектория все еще находит их. |
costs | costs/ | Смета стоимости изготовления траекторий. |
extra | любой путь | Текстовые файлы сохраняются дословно: рабочие процессы, README, сгенерированный G-код. |
Фиксация, ветвление, сравнение и слияние в коде
The Repository класс работает на любом сервере хранения. Sidecar поддерживает его с помощью SQLite (таблицы GitObject и GitRef); memoryBackend() используется для тестов и экспериментов. Следующий пример завершен, и его выходные данные показаны в комментариях.
import { Repository, memoryBackend, snapshotToFiles, describeDiff } from "@cadcamfun/vcs"
const repo = new Repository(memoryBackend())
const me = { name: "Ada", email: "ada@example.com", time: 1767225600, tz: "+0100" }
const files = (width: number, height: number) => snapshotToFiles({
project: { id: "p1", name: "Bracket" },
drawings: [{ id: "d1", name: "Plate", width, height }],
components: [], toolpaths: [],
})
const base = repo.commit(files(40, 25), { message: "base", author: me })
repo.currentBranch() // "main"
repo.createBranch("a"); repo.createBranch("b")
repo.checkout("a"); const a = repo.commit(files(50, 25), { message: "a: width 50", author: me })
repo.checkout("b"); repo.commit(files(40, 30), { message: "b: height 30", author: me })
describeDiff(repo, base, a)
// [{ path: "drawings/d1.json", kind: "drawings", id: "d1", name: "Plate",
// status: "modified", changes: [{ pointer: "/width", before: 40, after: 50 }] }]
repo.mergeInto("a", "b", me) // { kind: "merge", oid: "46e7…" }
// different properties of the same entity merge cleanly
repo.checkout("b"); repo.commit(files(60, 30), { message: "b: width 60", author: me })
repo.mergeInto("a", "b", me)
// { kind: "conflict", conflicts: [{ path: "drawings/d1.json", pointers: ["/width"] }] }
repo.createBranch("bad..name") // throws: Invalid branch name bad..name
repo.commit(sameFilesAsHead, { message: "x", author: me })
// throws: No changes since the last commit (unless allowEmpty: true) Слияния являются трехсторонними на уровне свойств JSON. Когда обе стороны изменили разные свойства одного объекта, слияние завершается успешно. Когда оба изменили одно и то же свойство на разные значения, результатом будет conflict в котором перечислены указатели RFC 6901 внутри каждого файла. Массивы одинаковой длины сравниваются по индексу, поэтому перемещенная вершина отображается как одно изменение; массивы разной длины сравниваются как единое целое.
| Объединить результат | Значение |
|---|---|
up-to-date | Нечего объединять; возвращает текущий коммит. |
fast-forward | Указатель ветки переместился вперед; коммит слияния не был создан. |
merge | Был создан коммит слияния. |
conflict | Нет фиксации; conflicts перечисляет пути и указатели для разрешения. |
| Метод репозитория | Цель |
|---|---|
commit(files, { message, author, allowEmpty? }) | Запишите полное дерево в качестве нового коммита в текущей ветке. |
log(rev = "HEAD", limit?) / fileLog(path, rev?, limit?) | История ветки/одного файла. |
createBranch(name, from = "HEAD"), deleteBranch, checkout | Управление филиалом. Имена не должны содержать .. или //, закончиться на / или .lockили содержать @{. |
tag(name, rev = "HEAD"), tags() | Легкие теги под refs/tags/. |
diff(from, to) | Изменения на уровне файлов: добавление, изменение, удаление с идентификаторами больших двоичных объектов. |
restorePaths(rev, paths, author, message?) | Новый коммит, восстанавливающий выбранные файлы из старой версии. |
revertTo(rev, author, message?) | Новый коммит, дерево которого соответствует более старой версии; история не переписывается. |
merge(theirs, author) / mergeInto(into, theirs, author) | Трехстороннее слияние с текущей/именованной веткой. |
isAncestor, mergeBase | Графовые запросы. |
Правила, применяемые приложением
Служба истории проектов боковой панели добавляет правила поверх репозитория:
| Код неисправности | Когда |
|---|---|
blocked | Актер ИИ пытается зафиксировать или слиться main (в сообщении говорится, что нужно использовать ai/* ветку и откройте запрос на включение), или запрос на включение объединяется, пока последний вердикт рецензента request-changes. |
dirty | В рабочей копии есть незафиксированные изменения, и операция перезапишет их: «Незафиксированные изменения в N файлах; сначала зафиксируйте или отмените их». |
conflict | Слияние привело к конфликтам; сбой содержит список конфликтов. |
nothing-to-commit | Дерево не изменилось с момента последнего коммита. |
not-found | Неизвестная ветка, фиксация, объект или запрос на включение. |
remote | Синхронизация GitHub не удалась. |
invalid | Другой недопустимый ввод, например просмотр или объединение запроса на включение, который не открыт. |
Учитывается только последний вердикт каждого рецензента без комментариев. Рецензент, запросивший изменения и позднее утвердивший их, больше не блокирует слияние. Коммиты, события запросов на включение и обзоры публикуются как текущие события, поэтому рабочий стол и сопутствующий контент обновляются без опроса.
Байт-совместим с git
Идентификаторы объектов вычисляются точно так же, как их вычисляет git. При отправке на GitHub через Git Data API все идентификаторы коммитов остаются идентичными с обеих сторон, а git clone зеркала показывает ту же историю, что и приложение. GitHub принимает только ускоренные обновления ссылок; сначала вытащите и объедините локально, когда пульт переместится.
Настоящий объект фиксации
{
"oid": "44d2d03d23b27fbbc4b388e32e15dfb0f39fff87",
"parents": [],
"message": "First version\n",
"author": { "name": "Local user", "email": "local@cadcamfun.local", "time": 1792037121 }
} oid— это 40-символьный шестнадцатеричный идентификатор объекта фиксации, хранящегося вGitObject.- У первого коммита нет родителей; коммит слияния имеет два.
- Сообщение сохраняется с завершающим символом новой строки, как это делает Git.
- Без
x-session-token, автором является локальный профиль установки.timeнаходится в секундах Unix.
| Маршрут | Тело | Необходимый |
|---|---|---|
POST …/vcs/commit | message, authorKind, files | message |
POST …/vcs/branches | name, from | name |
POST …/vcs/checkout | branch | branch |
POST …/vcs/restore | rev, paths | rev |
POST …/pulls | title, body, head, base, authorKind | title, head |