Перейти к содержанию
CADCAMFUN
Документы

Документация

История проекта

Локальные снимки проекта, совместимые с Git, структурные различия, проверяемые ветки и дополнительное зеркалирование GitHub.

Автоматически переведено с английского. Смотреть оригинал на английском

Рабочая копия и история

Записи SQLite приложения являются текущей рабочей копией проекта. @cadcamfun/vcs хранит Git-совместимые объекты, деревья, коммиты и ссылки через внедренный объектный бэкэнд; сайдкар сохраняет этот бэкэнд в SQLite. Операции с историей работают локально без исполняемого файла Git или учетной записи GitHub.

Коммит делает снимок проекта и связанных с ним ресурсов проектирования/производства. Ветки указывают на коммиты, а HEAD идентифицирует извлеченную ветку. Таблицы версий ресурсов сосуществуют с этой историей уровня проекта; версия чертежа и фиксация проекта имеют разные области действия.

Рабочий процесс фиксации и ветвления

  1. Читать GET /api/projects/:id/vcs/status чтобы увидеть текущую ветку HEAD и измененные пути.
  2. Создайте ветку с POST /vcs/branches, затем проверьте это с помощью POST /vcs/checkout. Пути ветвей здесь указаны относительно префикса API проекта.
  3. Отредактируйте ресурсы проекта и зафиксируйте их с помощью POST /vcs/commit и непустое сообщение.
  4. Осмотреть GET /vcs/log и GET /vcs/diff. Журнал поддерживает версию, ограничение и дополнительный отслеживаемый путь.
  5. Откройте запрос на включение проекта, просмотрите его структурные изменения и выполните слияние после разрешения блокирующих проверок или конфликтов.

Извлечение, восстановление и операции, перемещающие рабочую ветвь, отказываются от грязной рабочей копии там, где это необходимо. При восстановлении записывается новая фиксация, представляющая более ранний контент, при необходимости ограниченная выбранными путями. Он сохраняет последующую историю, а не переписывает ее.

Содержимое снимка

Макет репозитория проекта
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.json рисунки/<id>.jsonкомпоненты/<id>.json траектории/<id>.jsonматериалы/<id>.json инструменты/<id>.jsonмашинные конфигурации/<id>.json затраты/<id>.json .cadcamfun/workflows/<имя>.yml один файл на объект → различия и слияния остаются локальными для того, что изменилось
Список снимковКаталогСодержание
projectproject.jsonМетаданные проекта.
drawings, components, toolpathsте же именаПроектные и производственные предприятия.
materials, tools, machineConfigsmaterials/, tools/, machine-configs/Элементы библиотеки, на которые ссылаются траектории, имеют версию проекта, поэтому восстановленная траектория все еще находит их.
costscosts/Смета стоимости изготовления траекторий.
extraлюбой путьТекстовые файлы сохраняются дословно: рабочие процессы, README, сгенерированный G-код.

Фиксация, ветвление, сравнение и слияние в коде

The Repository класс работает на любом сервере хранения. Sidecar поддерживает его с помощью SQLite (таблицы GitObject и GitRef); memoryBackend() используется для тестов и экспериментов. Следующий пример завершен, и его выходные данные показаны в комментариях.

history-demo.ts
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 принимает только ускоренные обновления ссылок; сначала вытащите и объедините локально, когда пульт переместится.

Настоящий объект фиксации

POST /api/projects/:id/vcs/commit
{
  "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/commitmessage, authorKind, filesmessage
POST …/vcs/branchesname, fromname
POST …/vcs/checkoutbranchbranch
POST …/vcs/restorerev, pathsrev
POST …/pullstitle, body, head, base, authorKindtitle, head

Через 3Д

График фиксации Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
The last 14 commits of origin/main from git log --format=%h|%p: each pull request branch commit (back lane) is merged into main (front lane, orange merge commits), then the docs commits. A project history in the app is the same kind of graph: commits with parents, refs pointing at them.