Saltar al contenido
CADCAMFUN
Documentos

Documentación

Historia del proyecto

Instantáneas de proyectos locales compatibles con Git, diferencias estructurales, ramas revisables y duplicación de GitHub opcional.

Traducido automáticamente del inglés. Ver el original en inglés

Copia de trabajo e historial.

Los registros SQLite de la aplicación son la copia de trabajo del proyecto actual. @cadcamfun/vcs almacena blobs, árboles, confirmaciones y referencias compatibles con Git a través de un backend de objetos inyectados; el sidecar persiste en ese backend en SQLite. Las operaciones del historial funcionan localmente sin un ejecutable de Git o una cuenta de GitHub.

Una confirmación captura una instantánea del proyecto y sus recursos de diseño/fabricación relacionados. Las ramas apuntan a confirmaciones, mientras que HEAD identifica la rama retirada. Las tablas de versiones de recursos coexisten con este historial a nivel de proyecto; una versión de dibujo y una confirmación de proyecto tienen alcances diferentes.

Confirmar y ramificar el flujo de trabajo

  1. Leer GET /api/projects/:id/vcs/status para ver la rama actual, HEAD y las rutas modificadas.
  2. Crea una rama con POST /vcs/branches, luego compruébalo con POST /vcs/checkout. Las rutas de las ramas aquí son relativas al prefijo API del proyecto.
  3. Edite los recursos del proyecto y comprométase con POST /vcs/commit y un mensaje no vacío.
  4. Inspeccionar GET /vcs/log y GET /vcs/diff. El registro admite una revisión, un límite y una ruta de seguimiento opcional.
  5. Abra una solicitud de extracción de proyecto, revise sus cambios estructurales y fusione después de resolver conflictos o revisiones de bloqueo.

Las operaciones de pago, restauración y que mueven la rama de trabajo rechazan una copia de trabajo sucia cuando sea necesario. Una restauración registra una nueva confirmación que representa el contenido anterior, limitada opcionalmente a las rutas seleccionadas. Preserva la historia posterior en lugar de reescribirla.

Contenido de la instantánea

Diseño del repositorio de proyectos
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

Un archivo JSON por entidad mantiene separados los cambios no relacionados. La instantánea incluye elementos de biblioteca a los que hacen referencia las trayectorias de herramientas y estimaciones de costos de producción para que los datos de fabricación restaurados puedan conservar sus dependencias. Los identificadores de entidad utilizados como nombres de archivos están restringidos a letras, dígitos, guiones bajos y guiones seguros, con un máximo de 128 caracteres.

Las claves JSON se ordenan de forma recursiva y los archivos utilizan una impresión bonita estable con una nueva línea final. Las matrices conservan su orden. Los archivos de texto adicionales pueden viajar con una instantánea a nivel de paquete; el punto final de confirmación pública acepta archivos adicionales solo bajo .cadcamfun/workflows/ con un nombre de archivo YAML seguro.

Los objetos usan el formato de objeto suelto de git byte por byte, por lo que los ID de los objetos coinciden con los calculados por git. Las entradas del árbol son archivos (modo 100644) o directorios (modo 40000). Una firma de confirmación registra el nombre, el correo electrónico, el tiempo en segundos Unix y un +hhmm/-hhmm compensar. Las ramas se almacenan bajo refs/heads/, y la rama predeterminada de un proyecto es main (packages/vcs/src/object.ts, repository.ts).

Diferenciar y fusionar semántica

El repositorio calcula una base de fusión, maneja los lados sin cambios directamente y realiza fusiones estructurales de tres vías para JSON modificado. Las ediciones independientes de propiedades de objetos se pueden fusionar sin conflictos. Las ediciones incompatibles simultáneas en el mismo escalar o matriz se informan mediante punteros JSON; Las matrices no se fusionan elemento por elemento.

Las diferencias de entidad incluyen ruta, tipo de recurso, identificador y nombre cuando estén disponibles, estado agregado/modificado/eliminado y cambios de propiedad con valores anteriores/después. Los archivos que no son JSON utilizan un comportamiento de conflicto a nivel de archivo. Una fusión de repositorio con conflictos devuelve sus rutas y punteros sin escribir una confirmación fusionada.

Solicitudes de extracción y permisos

Solicitudes de extracción de proyectos disponibles en /api/projects/:id/pulls. Al abrir uno se registra un título, cuerpo, encabezado, base y tipo de autor. Las respuestas detalladas incluyen la solicitud de extracción, revisiones y cambios. Soporte de reseñas comment, approve, y request-changes, con ruta opcional y puntero de propiedad.

El último veredicto de no comentario por revisor controla un bloque de solicitud de cambios. Se rechaza una fusión mientras dicho veredicto solicite cambios. La implementación no requiere aprobación positiva cuando no existe sentencia de bloqueo. Las diferencias de solicitud de extracción fusionadas utilizan la confirmación de fusión registrada, por lo que el movimiento de rama posterior no cambia ese registro de revisión.

Leer el historial, confirmar, bifurcar, abrir solicitudes de extracción y revisar requieren acceso al proyecto. Los movimientos de copias de trabajo y el mantenimiento de sucursales compartidas requieren que el propietario o un administrador/gerente de la organización lo exija el controlador. Las operaciones sucias o conflictivas devuelven 409; las acciones protegidas devuelven 403; las referencias o recursos faltantes devuelven 404; otras operaciones no válidas devuelven 400.

Un actor de IA no puede comprometerse, restaurarse o fusionarse en main. El asistente utiliza una rama de propuesta y abre una solicitud de extracción para que una persona la revise. Los registros de auditoría y notificación identifican los cambios originados por el asistente.

Espejo GitHub opcional

GET y PUT /api/projects/:id/vcs/remote leer o configurar un owner/repo espejo de GitHub; null lo separa. Uso de empujar y tirar POST /vcs/push y /vcs/pull, con el token de GitHub del usuario en x-github-token para esa llamada.

Push transfiere objetos accesibles y actualiza la rama remota sin sobrescribir las confirmaciones remotas no extraídas. Pull recupera la rama remota y la fusiona localmente, rechazando una copia de trabajo sucia. Las ediciones JSON divergentes e incompatibles devuelven conflictos en lugar de reemplazar silenciosamente el contenido local.

El transporte sidecar utiliza operaciones de referencia/objeto REST de GitHub. El token de GitHub se proporciona por solicitud y no se almacena como datos del proyecto. Una solicitud de extracción local es un registro de revisión de aplicaciones; no es automáticamente una solicitud de extracción de GitHub.

Instantáneas y restauración.

snapshotToFiles convierte una instantánea del proyecto en contenido de archivo canónico; filesToSnapshot reconstruye las listas de dominios. ProjectVcsRepo lee los recursos de la base de datos actual y aplica instantáneas restauradas. La restauración de todo el proyecto puede cambiar varias tablas relacionadas, así que revise su diferencia y borre la copia de trabajo antes de cambiar el historial.

API de transporte y objetos

El paquete VCS exporta codificación y lectura de objetos, Repository, adaptadores de tienda, JSON canónico y ayudantes de fusión, conversión de instantáneas, diferencias de entidades, sincronización de GitHub e interfaces de transporte. Las pruebas pueden inyectar un backend de objeto en memoria o un transporte falso en lugar de acceder al repositorio de un usuario.

Puntos de entrada de implementación

packages/vcs/src/repository.ts posee confirmaciones, referencias, recorridos, restauración y fusiones; json.ts posee fusión estructural; snapshot.ts define los recursos rastreados; diff.ts describe cambios de entidad; github.ts y transport.ts implementar la duplicación. Sidecar project-vcs.ts añade política de actor y persistencia, mientras http/vcs.ts suministros autorización de transporte y eventos.

Operaciones históricas y automatización.

Las definiciones de flujo de trabajo se versionan con el proyecto y se ejecutan en archivos confirmados. Una confirmación puede desencadenar esos flujos de trabajo después de que se haya registrado el historial; un flujo de trabajo fallido no deshace la confirmación. Mantenga distintos los guardados de recursos locales, las confirmaciones de proyectos, los resultados del flujo de trabajo y la sincronización remota al diagnosticar el estado de un proyecto.

Prueba el repositorio sin datos de la aplicación

La unión del almacén de objetos permite que un ejercicio de integración se confirme y se bifurque completamente en la memoria. Ejecute esto dentro de un espacio de trabajo que depende de @cadcamfun/vcs, como apps/sidecar. No toca la base de datos del proyecto del escritorio.

Dos confirmaciones y una rama de propuesta.
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 recibe el árbol de archivos completo para esa confirmación, no un parche. El sidecar construye este árbol a partir de registros de bases de datos de trabajo y archivos de texto transportados. Una integración a nivel de paquete debe conservar los archivos que pretende conservar. El ejemplo en memoria no aplica la propiedad del sidecar ni la política de actor de IA; estos son aplicados por el servicio del proyecto y la capa HTTP.

Fuente: packages/vcs/src/store.ts, repository.ts, y apps/sidecar/src/services/project-vcs.ts.

Revisar, restaurar y sincronizar deliberadamente

Registre los cambios en la copia de trabajo antes de cambiar de sucursal. Una nueva rama requiere una confirmación de fuente resoluble, por lo tanto, inicialice un proyecto no comprometido con su primera confirmación antes de realizar la rama. Crear una rama solo crea una referencia; checkout es una operación separada que aplica su instantánea a la base de datos de trabajo.

Para una solicitud de extracción, compare el encabezado con su base de fusión y revise las diferencias a nivel de propiedad. Un comentario posterior no borra un veredicto de cambios de solicitud anterior: el revisor debe enviar un veredicto de aprobación posterior. Un PR fusionado puede avanzar rápidamente o crear una confirmación de fusión según la ascendencia del repositorio; inspeccione la confirmación de fusión registrada en lugar de asumir un número fijo de padres.

Al fusionarse con la base registrada, el servicio requiere una copia de trabajo limpia y aplica la nueva instantánea de la base. Cuando se retira otra rama, la combinación de la base del PR actualiza la referencia de esa rama sin reemplazar la base de datos de trabajo actual. Un pago posterior carga esa base actualizada.

Push y pull sincronizan el historial comprometido. El contenido de la interfaz de usuario no guardado y el estado de la base de datos no confirmada no son instantáneas remotas. Un rechazo remoto es una solicitud para buscar/fusionar primero; no es una instrucción para sobrescribir la rama remota.

Fuente: packages/vcs/src/repository.ts, github.ts, y apps/sidecar/src/services/project-vcs.ts.

Recuperarse de los fallos del historial

FallaSiguiente acción
NothingToCommitCompare archivos de trabajo de bases de datos con HEAD. Guardar nuevamente los mismos valores de recursos no crea un árbol diferente.
Sucursal inválida o existenteElija un nuevo nombre de referencia seguro. Los nombres no pueden contener cruces, barras dobles, fragmentos de expresión ref ni una barra diagonal final/sufijo .lock.
Cambios no confirmadosConfirme o restaure/descarte deliberadamente los recursos previstos antes de realizar la extracción, la extracción o una operación de copia de trabajo protegida.
Fusionar conflicto con ruta/punterosInspeccione esas propiedades en los historiales de base/cabeza, cree una resolución revisada y vuelva a intentarlo. La fusión fallida del repositorio no creó una confirmación de fusión parcial.
Un revisor solicitó cambiosResuelva los comentarios y obtenga un veredicto actualizado sin comentarios de ese revisor.
Los actores de la IA no pueden actuar en los principalesUtilice una rama de propuesta de IA y una solicitud de extracción revisada por humanos. Cambiar un indicador de confirmación no elimina la restricción del actor.

Fuente: packages/vcs/src/repository.ts, apps/sidecar/src/services/project-vcs.ts, y http/vcs.ts. El Referencia API enumera los esquemas de solicitud y respuesta reales.

Diseño del repositorio

Un proyecto se almacena en el repositorio como un archivo JSON por entidad. Por lo tanto, la edición de un dibujo nunca toca un archivo de ruta de herramienta y el diseño se lee de forma natural en GitHub. snapshotToFiles escribe este diseño desde un ProjectSnapshot, y filesToSnapshot lo vuelve a leer.

/ project.json dibujos/<id>.jsoncomponentes/<id>.json rutas de herramienta/<id>.jsonmateriales/<id>.json herramientas/<id>.jsonconfiguraciones-máquina/<id>.json costos/<id>.json .cadcamfun/workflows/<nombre>.yml un archivo por entidad → las diferencias y fusiones permanecen locales respecto de lo que cambió
Lista de instantáneasDirectorioContenido
projectproject.jsonMetadatos del proyecto.
drawings, components, toolpathsmismos nombresEntidades de diseño y fabricación.
materials, tools, machineConfigsmaterials/, tools/, machine-configs/Elementos de biblioteca a los que hacen referencia las trayectorias, versionados con el proyecto para que una trayectoria restaurada aún los encuentre.
costscosts/Estimaciones de costos de producción de las trayectorias.
extracualquier caminoArchivos de texto almacenados palabra por palabra: flujos de trabajo, README, código G generado.

Confirmar, bifurcar, diferenciar y fusionar en código

El Repository la clase funciona en cualquier backend de almacenamiento. El sidecar lo respalda con SQLite (tablas GitObject y GitRef); memoryBackend() se utiliza para pruebas y experimentos. El siguiente ejemplo está completo y su resultado se muestra en los comentarios.

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)

Las fusiones son triples a nivel de propiedades JSON. Cuando ambas partes cambiaron diferentes propiedades de una entidad, la fusión se realiza correctamente. Cuando ambos cambiaron la misma propiedad a valores diferentes, el resultado es un conflict que enumera los punteros RFC 6901 dentro de cada archivo. Las matrices de igual longitud se comparan por índice, por lo que un vértice movido se muestra como un cambio; las matrices de diferentes longitudes se comparan en su conjunto.

Resultado de fusiónSignificado
up-to-dateNada que fusionar; devuelve la confirmación actual.
fast-forwardEl puntero de la rama avanzó; no se creó ninguna confirmación de fusión.
mergeSe creó una confirmación de fusión.
conflictSin compromiso; conflicts enumera rutas y punteros para resolver.
Método de repositorioObjetivo
commit(files, { message, author, allowEmpty? })Escriba un árbol completo como una nueva confirmación en la rama actual.
log(rev = "HEAD", limit?) / fileLog(path, rev?, limit?)Historial de la sucursal / de un archivo.
createBranch(name, from = "HEAD"), deleteBranch, checkoutGestión de sucursales. Los nombres no deben contener .. o //, terminar en / o .lock, o contener @{.
tag(name, rev = "HEAD"), tags()Etiquetas ligeras debajo refs/tags/.
diff(from, to)Cambios a nivel de archivo: agregados, modificados, eliminados, con ID de blob.
restorePaths(rev, paths, author, message?)Nueva confirmación que restaura archivos seleccionados de una revisión anterior.
revertTo(rev, author, message?)Nueva confirmación cuyo árbol equivale a una revisión anterior; la historia no se reescribe.
merge(theirs, author) / mergeInto(into, theirs, author)Fusión de tres vías en la rama actual/una rama con nombre.
isAncestor, mergeBaseConsultas de gráficos.

Reglas impuestas por la aplicación.

El servicio de historial de proyectos del sidecar agrega reglas además del repositorio:

código de fallaCuando
blockedUn actor de IA intenta comprometerse o fusionarse main (el mensaje dice que use un ai/* bifurcar y abrir una solicitud de extracción), o se fusiona una solicitud de extracción mientras se publica el último veredicto de un revisor. request-changes.
dirtyLa copia de trabajo tiene cambios no confirmados y la operación los sobrescribiría: "Cambios no confirmados en N archivos; confírmelos o deséchelos primero".
conflictUna fusión produjo conflictos; el fracaso lleva la lista de conflictos.
nothing-to-commitEl árbol no ha cambiado desde la última confirmación.
not-foundRama, confirmación, objeto o solicitud de extracción desconocidos.
remoteLa sincronización de GitHub falló.
invalidOtras entradas no válidas, por ejemplo, revisar o fusionar una solicitud de extracción que no está abierta.

Sólo cuenta el último veredicto de cada revisor sin comentarios. Un revisor que solicitó cambios y luego los aprobó ya no bloquea la combinación. Las confirmaciones, los eventos de solicitud de extracción y las revisiones se publican como eventos en vivo, por lo que el escritorio y el complemento se actualizan sin sondeo.

Compatible con bytes con git

Los ID de objeto se calculan exactamente como los calcula git. Enviar a GitHub a través de Git Data API mantiene todos los ID de confirmación idénticos en ambos lados, y un git clone del espejo muestra el mismo historial que la aplicación. GitHub sólo acepta actualizaciones de referencia de avance rápido; tire y combine localmente primero cuando el control remoto se haya movido.

Un objeto de compromiso real

ENVIAR /api/projects/:id/vcs/commit
{
  "oid": "44d2d03d23b27fbbc4b388e32e15dfb0f39fff87",
  "parents": [],
  "message": "First version\n",
  "author": { "name": "Local user", "email": "local@cadcamfun.local", "time": 1792037121 }
}
  • oid es un ID hexadecimal de 40 caracteres del objeto de confirmación almacenado en GitObject.
  • El primer compromiso no tiene padres; una confirmación de fusión tiene dos.
  • El mensaje se almacena con una nueva línea al final, como lo hace Git.
  • sin un x-session-token, el autor es el perfil local de la instalación. time está en segundos de Unix.
RutaCuerpoRequerido
POST …/vcs/commitmessage, authorKind, filesmessage
POST …/vcs/branchesname, fromname
POST …/vcs/checkoutbranchbranch
POST …/vcs/restorerev, pathsrev
POST …/pullstitle, body, head, base, authorKindtitle, head

En 3D

Un gráfico de confirmación Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
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.