コンテンツへスキップ
CADCAMFUN
ドキュメント

ドキュメント

プロジェクトの歴史

ローカルの Git 互換プロジェクト スナップショット、構造差分、レビュー可能なブランチ、およびオプションの GitHub ミラーリング。

英語から自動翻訳されています。 英語の原文を見る

作業用コピーと履歴

アプリケーションの SQLite レコードは、現在のプロジェクトの作業コピーです。 @cadcamfun/vcs 挿入されたオブジェクト バックエンドを通じて Git 互換の BLOB、ツリー、コミット、および参照を保存します。サイドカーはそのバックエンドを 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

エンティティごとに 1 つの JSON ファイルが、無関係な変更を分離して保持します。スナップショットには、ツールパスによって参照されるライブラリ項目と製造コストの見積もりが含まれるため、復元された製造データはその依存関係を保持できます。ファイル名として使用されるエンティティ識別子は、安全な文字、数字、アンダースコア、ハイフンに制限されており、最大文字数は 128 文字です。

JSON キーは再帰的にソートされ、ファイルは最後の改行を含む安定した整形印刷を使用します。配列は順序を保持します。追加のテキスト ファイルは、パッケージ レベルのスナップショットとともに送信される可能性があります。パブリック コミット エンドポイントは、次の環境でのみ追加のファイルを受け入れます。 .cadcamfun/workflows/ 安全な YAML ファイル名を使用してください。

オブジェクトは git のルーズオブジェクト形式をバイトごとに使用するため、オブジェクト ID は、によって計算されたものと一致します。 git。ツリー エントリはいずれかのファイル (モード 100644) またはディレクトリ (モード 40000)。コミット署名には、名前、電子メール、Unix 秒時間、および +hhmm/-hhmm オフセット。ブランチは以下に保存されます refs/heads/、プロジェクトのデフォルトのブランチは main (packages/vcs/src/object.ts, repository.ts).

差分とマージのセマンティクス

リポジトリはマージ ベースを計算し、変更されていない側を直接処理し、変更された JSON に対して構造的な 3 方向のマージを実行します。独立したオブジェクトとプロパティの編集は、競合することなくマージできます。同じスカラーまたは配列に対する互換性のない同時編集は、JSON ポインターを通じて報告されます。配列は要素ごとにマージされません。

エンティティの差分には、パス、リソースの種類、識別子と名前 (使用可能な場合)、追加/変更/削除のステータス、前後の値を含むプロパティの変更が含まれます。非 JSON ファイルはファイルレベルの競合動作を使用します。競合のあるリポジトリのマージは、マージされたコミットを書き込まずに、そのパスとポインタを返します。

プルリクエストと権限

プロジェクトのプル リクエストは次の場所で公開されています /api/projects/:id/pulls。開くと、タイトル、本文、頭、ベース、著者の種類が記録されます。詳細応答には、プル リクエスト、レビュー、変更が含まれます。レビューのサポート comment, approve、 そして request-changes、オプションのパスとプロパティ ポインターを使用します。

レビュー担当者ごとの最新の非コメント判定により、変更要求ブロックが制御されます。マージは、そのような判定要求が変更されている間は拒否されます。阻止の評決がない場合、実装に積極的な承認は必要ありません。マージされたプルリクエストの差分では、記録されたマージ コミットが使用されるため、後でブランチを移動してもレビュー レコードは変更されません。

履歴の読み取り、コミット、分岐、プル リクエストのオープン、レビューにはプロジェクトへのアクセスが必要です。作業コピーの移動と共有ブランチのメンテナンスには、ハンドラーによって強制される所有者または組織管理者/マネージャーが必要です。ダーティな操作または競合する操作は 409 を返します。保護されたアクションは 403 を返します。参照またはリソースが欠落している場合は、404 が返されます。他の無効な操作は 400 を返します。

AI アクターはコミット、復元、またはマージできません。 main。アシスタントは提案ブランチを使用して、レビューする人にプル リクエストを開きます。監査および通知レコードにより、アシスタントによる変更が特定されます。

オプションの GitHub ミラー

GET そして PUT /api/projects/:id/vcs/remote 読み取りまたは設定 owner/repo GitHub ミラー。 null はそれを切り離します。押して引いて使用する POST /vcs/push そして /vcs/pull、ユーザーの GitHub トークンを含む x-github-token その電話のために。

プッシュは、到達可能なオブジェクトを転送し、プルされていないリモート コミットを上書きせずにリモート ブランチを更新します。プルはリモート ブランチを取得してローカルにマージし、ダーティな作業コピーを拒否します。互換性のない多様な JSON 編集は、ローカル コンテンツを黙って置き換えるのではなく、競合を返します。

サイドカー トランスポートは、GitHub REST オブジェクト/ref 操作を使用します。 GitHub トークンはリクエストごとに提供され、プロジェクト データとしては保存されません。ローカル プル リクエストはアプリケーションのレビュー レコードです。これは自動的には GitHub プル リクエストにはなりません。

スナップショットと復元

snapshotToFiles プロジェクトのスナップショットを正規ファイルのコンテンツに変換します。 filesToSnapshot ドメインリストを再構築します。 ProjectVcsRepo 現在のデータベース リソースを読み取り、復元されたスナップショットを適用します。プロジェクト全体の復元では複数の関連テーブルが変更される可能性があるため、履歴を切り替える前に差分を確認し、作業コピーをクリアしてください。

トランスポート API とオブジェクト 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。デスクトップのプロジェクト データベースには影響しません。

2 つのコミットと 1 つのプロポーザル ブランチ
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 パッチではなく、そのコミットの完全なファイル ツリーを受け取ります。サイドカーは、作業中のデータベース レコードと伝送されるテキスト ファイルからこのツリーを構築します。パッケージレベルの統合では、保持する予定のファイルを保持する必要があります。インメモリの例では、サイドカーの所有権や AI アクター ポリシーは適用されません。これらは、プロジェクト サービスと HTTP 層によって強制されます。

ソース: packages/vcs/src/store.ts, repository.ts、 そして apps/sidecar/src/services/project-vcs.ts.

意図的に確認、復元、同期する

ブランチを切り替える前に、作業コピーの変更を記録します。新しいブランチには解決可能なソース コミットが必要なので、ブランチする前に最初のコミットでコミットされていないプロジェクトを初期化します。ブランチを作成すると、参照のみが作成されます。チェックアウトは、スナップショットを作業データベースに適用する別の操作です。

プル リクエストの場合は、ヘッドとそのマージ ベースを比較し、プロパティ レベルの違いを確認します。後のコメントでは、以前の変更要求の判定はクリアされません。レビュー担当者は、その後の承認判定を送信する必要があります。マージされた PR は、リポジトリの祖先に従って早送りしたり、マージ コミットを作成したりできます。固定数の親を想定する代わりに、記録されたマージ コミットを検査します。

チェックアウトされたベースにマージする場合、サービスはクリーンな作業コピーを必要とし、新しいベース スナップショットを適用します。別のブランチがチェックアウトされると、PR のベースをマージすると、現在の作業データベースを置き換えることなく、そのブランチの参照が更新されます。後続のチェックアウトでは、その更新されたベースがロードされます。

プッシュとプルはコミットされた履歴を同期します。保存されていない UI コンテンツとコミットされていないデータベースの状態は、リモート スナップショットではありません。リモート先行拒否は、最初にフェッチ/マージする要求です。これはリモート ブランチを上書きする命令ではありません。

ソース: packages/vcs/src/repository.ts, github.ts、 そして apps/sidecar/src/services/project-vcs.ts.

履歴障害からの回復

失敗次のアクション
NothingToCommitデータベース作業ファイルを HEAD と比較します。同じリソース値を再度保存しても、別のツリーは作成されません。
無効なブランチまたは既存のブランチ新しい安全な参照名を選択してください。名前には、トラバーサル、二重スラッシュ、ref 式のフラグメント、または末尾のスラッシュ/.lock 接尾辞を含めることはできません。
コミットされていない変更チェックアウト、プル、または保護された作業コピー操作の前に、目的のリソースをコミットするか、意図的に復元/破棄します。
パス/ポインターとのマージ競合ベース/ヘッド履歴内のこれらのプロパティを検査し、レビュー済みの解決策を作成して、再試行してください。失敗したリポジトリのマージでは、部分的なマージ コミットが作成されませんでした。
レビュー担当者が変更をリクエストしましたフィードバックを解決し、そのレビュー担当者から最新の非コメント評決を取得します。
AI アクターはメインで行動することはできませんAI プロポーザル ブランチと人間がレビューしたプル リクエストを使用します。確認フラグを変更しても、アクターの制限は解除されません。

ソース: packages/vcs/src/repository.ts, apps/sidecar/src/services/project-vcs.ts、 そして http/vcs.ts。の APIリファレンス 実際のリクエストとレスポンスのスキーマをリストします。

リポジトリのレイアウト

プロジェクトは、エンティティごとに 1 つの JSON ファイルとしてリポジトリに保存されます。したがって、図面の編集ではツールパス ファイルに触れることがなく、レイアウトは GitHub 上で自然に読み込まれます。 snapshotToFiles このレイアウトを ProjectSnapshot、 そして filesToSnapshot それを読み返します。

/ project.json 図面/<id>.jsonコンポーネント/<id>.json ツールパス/<id>.jsonマテリアル/<id>.json tools/<id>.jsonmachine-configs/<id>.json コスト/<id>.json .cadcamfun/workflows/<名前>.yml エンティティごとに 1 つのファイル → 差分とマージは変更内容に対してローカルに留まります
スナップショットリストディレクトリコンテンツ
projectproject.jsonプロジェクトのメタデータ。
drawings, components, toolpaths同じ名前設計および製造エンティティ。
materials, tools, machineConfigsmaterials/, tools/, machine-configs/ツールパスが参照するライブラリ項目。プロジェクトとともにバージョン管理されるため、復元されたツールパスでもそれらの項目が見つかります。
costscosts/ツールパスの製造コストの見積もり。
extraどの道でもテキスト ファイルはそのまま保存されます: ワークフロー、README、生成された G コード。

コードでのコミット、分岐、差分、マージ

の Repository クラスはあらゆるストレージ バックエンドで動作します。サイドカーは 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 プロパティのレベルで 3 方向です。両方の側が 1 つのエンティティの異なるプロパティを変更すると、マージは成功します。両方が同じプロパティを異なる値に変更した場合、結果は次のようになります。 conflict これは、各ファイル内の RFC 6901 ポインターをリストします。同じ長さの配列がインデックスごとに比較されるため、移動された頂点は 1 つの変更として表示されます。異なる長さの配列は全体として比較されます。

マージ結果意味
up-to-dateマージするものは何もありません。現在のコミットを返します。
fast-forward分岐ポインタが前方に移動しました。マージコミットは作成されませんでした。
mergeマージコミットが作成されました。
conflictコミットはありません。 conflicts 解決するパスとポインタをリストします。
リポジトリメソッド目的
commit(files, { message, author, allowEmpty? })現在のブランチに新しいコミットとして完全なツリーを書き込みます。
log(rev = "HEAD", limit?) / fileLog(path, rev?, limit?)ブランチ/1 つのファイルの履歴。
createBranch(name, from = "HEAD"), deleteBranch, checkout支店管理。名前に次の内容を含めることはできません .. または //、で終わる / または .lock、または含む @{.
tag(name, rev = "HEAD"), tags()下の軽量タグ refs/tags/.
diff(from, to)ファイル レベルの変更: BLOB ID を使用した追加、変更、削除。
restorePaths(rev, paths, author, message?)選択したファイルを古いリビジョンから復元する新しいコミット。
revertTo(rev, author, message?)ツリーが古いリビジョンに等しい新しいコミット。歴史は書き換えられない。
merge(theirs, author) / mergeInto(into, theirs, author)現在のブランチ/名前付きブランチへの 3 者間マージ。
isAncestor, mergeBaseグラフクエリ。

アプリケーションによって適用されるルール

サイドカーのプロジェクト履歴サービスは、リポジトリ上にルールを追加します。

障害コードいつ
blockedAI アクターがコミットまたはマージを試みる main (メッセージには、 ai/* ブランチしてプル リクエストを開く)、またはレビュアーの最新の判断が下されている間にプル リクエストがマージされる request-changes.
dirty作業コピーにはコミットされていない変更があり、「N ファイルにコミットされていない変更があります。最初にコミットまたは破棄してください」という操作によってそれらが上書きされます。
conflictマージにより競合が発生しました。障害には競合リストが含まれます。
nothing-to-commitツリーは最後のコミット以来変更されていません。
not-found不明なブランチ、コミット、オブジェクト、またはプル リクエスト。
remoteGitHub の同期に失敗しました。
invalidその他の無効な入力。たとえば、オープンされていないプル リクエストのレビューやマージなど。

各査読者の最新のコメントなしの評決のみが考慮されます。変更をリクエストし、後で承認されたレビュー担当者は、マージをブロックしなくなりました。コミット、プル リクエスト イベント、レビューはライブ イベントとして公開されるため、デスクトップとコンパニオンはポーリングなしで更新されます。

git とのバイト互換性

オブジェクト ID は、git が計算するのとまったく同じように計算されます。 Git Data API を介して GitHub にプッシュすると、すべてのコミット ID が両側で同一に保たれます。 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 文字の 16 進数 ID です。 GitObject.
  • 最初のコミットには親がありません。マージコミットには 2 つあります。
  • メッセージは、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

3Dで

コミットグラフ ドラッグして周回します · スクロールしてズーム · 右ドラッグしてパンします
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.