Skip to content

Git interoperability ​

Git stays the human-facing system of record for review and delivery. Gin touches it only when the two are synchronised. This page describes the model Gin is built around, then what the current release actually ships.

The model: one diff, one checkpoint ​

The agents-not-humans principle fixes how the two systems relate:

  • Git commits are not Gin nodes. Gin history is its own: many checkpoints, forks and joins that Git never sees. Gin does not mirror or walk Git history.
  • No Git human metadata in Gin. No commit messages, authors, committer dates or porcelain conventions. Intent and context live in Gin's structured metadata and annotations.
  • Import: Gin finds the last Git commit it synchronised with, takes one diff from there to the new Git head, and records exactly one checkpoint, however many commits or merges Git gained in between.
  • Export: Gin applies its diff since the last sync onto that commit's Git tree and writes one Git commit. The caller supplies the commit message, because Git's readers are human; Gin does not keep it.
  • Mapping: one sync record (Gin checkpoint, Git commit, ref, direction, time) is the only link between the two.
  • If the Git ref moved since the last sync, export refuses. The caller imports, merges in Gin, then exports, so Git only ever fast-forwards from Gin.
  • Work per sync is proportional to the change. An import or export reads and writes only changed files and their ancestor directories.

In progress

The sync-level import and export above is the accepted design. Its implementation is being redesigned and is not yet on the main line. The current release ships the bundle-based adapter described below, which still keeps per-commit SHA mappings. Earlier documentation of "authored Git imports" that interprets Git history and merge parents is superseded.

What ships today ​

Gin's Git adapter is the only component that reads Git. Gin's own model never contains a Git object, ref or SHA: Git commit names appear only as external keys of Git-import checkpoints and in mappings kept beside them. Gin workspaces contain no .git directory, and a Git checkout alone cannot publish or advance in Gin.

Enabling the Git endpoint ​

sh
gin serve --listen 0.0.0.0:7400 --data /var/lib/gin --auth /etc/gin/auth.conf \
  --tls-cert-file /etc/gin/server-chain.pem --tls-key-file /etc/gin/server-key.pem \
  --git-listen 127.0.0.1:7401 --git-project myproject=gin:blake3:v1:repository:<hex>

Each --git-project binds a project name to one Gin repository. The endpoint speaks HTTP/1.1 and uses HTTPS whenever a TLS pair is configured. Grants:

GrantAllows
git_importsending bundles and answering history requests
git_exportexporting checkpoints to the Gin-owned repository
read_manifestrecording and following history requests

Import: Gin fetches nothing ​

Gin never fetches from a remote. A client sends each tip as a Git bundle with its exact base to POST /v1/git/import, as a multipart body with a versioned JSON envelope and the bundle. Gin verifies the bundle with stock Git, derives the tip's tree, and acknowledges only once that tree is complete and durably stored. A repeated send with the same bundle is answered again with replayed: true.

Refusals are structured (missing-objects, invalid-envelope, invalid-bundle, unauthorized, unknown-project, too-large, busy) and acknowledge nothing. A Git-import checkpoint is a pure function of repository and commit, so its identity never changes as more history arrives. Imported checkpoints can be read with ReadManifest and ReadBlobs like any snapshot.

Paths Gin refuses (such as a .. component) or unknown modes make a commit unrepresentable rather than silently altered.

History on request ​

When Gin needs a commit it does not hold, it records a request at /v1/git/history. A client with git_import lists open requests and answers them by sending a bundle. Gin holds no Git credential of its own and never calls out.

Export ​

POST /v1/git/export (grant git_export) writes one exact checkpoint as a Git commit whose single parent is the supplied Git base, then updates a ref under refs/heads/ in a Gin-owned bare repository.

  • The request must state the ref's expected old value, or null to require a new branch. Omitting it is refused.
  • If the ref does not hold the expected value, the export is refused with 409 export-refused. Gin never overwrites a moved ref.
  • Gin writes raw blobs, trees and commits without a checkout, filters or line ending conversion, and independently re-derives the tree to check it.
  • Commit identity is deterministic for the checkpoint and base pair, so a retry produces the same commit.
  • No caller-supplied destination, remote credential or mirror is accepted. Gin's own Git repositories refuse git push and git fetch.

Calling the endpoints ​

gin git-http is a small client for these routes. It applies the same TLS, CA and plaintext policy as the RPC client:

sh
gin git-http --endpoint https://gin.internal:7401/v1/git/import \
  --token-file /private/client.token --ca-file /etc/gin/private-ca.pem \
  request --body-file ./send.multipart \
  --content-type 'multipart/form-data; boundary=send-boundary'

Use request --method GET for history polling. The output is one JSON object with status, body and connection facts. It never follows redirects.

CI and Git ​

CI jobs report results against Git commits. gin ci upload records the tested commit's object, tree and parents as provenance, so a CI observation can be recorded before any Git-to-Gin mapping exists. See Evidence.

Part of the Tama toolchain.