git

package
v1.801.256 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: Apache-2.0 Imports: 49 Imported by: 0

Documentation

Overview

browse.go — Hanzo Git's JSON read/browse surface: the machine-readable twin of the server-rendered UI (ui.go). The console repo-browser (hanzoai/console components/products/git) consumes THESE endpoints; ui.go serves the same data as HTML for a plain browser. Both read through the ONE Repository model (repository.go), so the two surfaces can never drift and neither knows which version-control system is underneath.

Routes (JSON, org-scoped — distinct trailing segments that never shadow the :org/:repo smart-HTTP protocol routes):

GET /v1/git/repos/:name/refs                 → { branches, tags, default }
GET /v1/git/repos/:name/tree?ref&path        → { entries: [ {name,path,type,size,mode} ] }
GET /v1/git/repos/:name/blob?ref&path        → { path,size,encoding,content,binary,truncated }
GET /v1/git/repos/:name/commits?ref&path&limit → { commits: [ {sha,shortSha,message,author*,date} ] }
GET /v1/git/repos/:name/readme?ref           → { path, content, encoding }

ref + path ride as ?ref=&path= QUERY params (the UI's own convention), so a slashed branch (feature/x) and a nested path are always unambiguous. Isolation is identical to the rest of git: the org is the gateway-minted, IAM-validated X-Org-Id (org(c)); a repo outside the caller's org is simply not found.

Package git mounts the Hanzo Cloud /v1/git surface: S3-backed Git hosting native in the unified cloud binary — Hanzo Git, the internal git host foundation agents push code into.

A repo is the Git LAYER (source code, buildable/deployable) that lives UNDER an IAM project. It is NOT the IAM project itself: `project` is org-scoping CONTEXT (org → project → env); a repo is scoped BY that context. Every repo belongs to exactly one org (the gateway-minted X-Org-Id, HIP-0026) and an optional project sub-scope (X-Project-Id), enforced on every query, so one org can never read, clone, push to, or delete another's repos.

Surface:

POST   /v1/git/repos            create a bare repo            -> repoView (201)
GET    /v1/git/repos            list the org's repos       -> {data:[repoView]}
GET    /v1/git/repos/:name      repo detail (branches, HEAD)  -> repoView
DELETE /v1/git/repos/:name      delete + purge storage        -> 204
GET    /v1/git/usage            per-repo + total bytes        -> usageView

Smart-HTTP git protocol (so `git clone` / `git push` work natively):

GET  /v1/git/:org/:repo/info/refs?service=git-upload-pack|git-receive-pack
POST /v1/git/:org/:repo/git-upload-pack     (clone/fetch)
POST /v1/git/:org/:repo/git-receive-pack    (push)

Storage is bare git repos on a real filesystem (osfs) rooted under {DataDir}/git; go-git initializes + reads them, while the heavy clone/push/ mirror paths stream through the `git` CLI (gitexec.go) so multi-GB packs stay bounded in memory. See storage.go for the hanzoai/vfs (S3) storage seam.

Billing: every repo tracks sizeBytes, re-measured on create and after each push. /v1/git/usage exposes per-repo + total bytes per org, and each measurement emits a "git.usage" log line a metering consumer can bill on.

gitbackend.go — git as ONE implementation of Repository (repository.go).

This is the only file on the read path that knows go-git exists. Everything go-git-shaped stops here: *gogit.Repository, *object.Commit, plumbing.Hash, filemode.FileMode. Readers above it see refs, revisions, trees and bytes.

The logic is lifted verbatim from the helpers this replaces (openGit, resolveRef, treeEntriesJSON, readmeAt, treeTextFiles) so the observable behaviour — ref-resolution fallbacks, dirs-before-files ordering, the binary check, the README candidate list — is unchanged. The one deliberate difference is that failures now come back as the model's sentinel errors instead of raw go-git errors, so a handler can tell "no such ref" from "this repository is broken" rather than reporting both as 404.

repository.go — the value at the centre of /v1/git: a Repository is a named, versioned content tree. Refs name revisions; a revision has a tree of paths; a path holds bytes. That is the whole model, and it is what every reader actually needs — the JSON browse surface (browse.go), the HTML twin (ui.go), and the code-intelligence feeder that hands content to /v1/code (index_on_push.go).

Git is ONE implementation of this model, not the model itself. It is a very good one — a content-addressed Merkle DAG, so the store falls out for free — but "revision" is a commit sha only because git says so; another backend may number its revisions or name them. Nothing above this file may assume otherwise, which is why Revision is an opaque string and why no go-git type (*gogit.Repository, *object.Commit, plumbing.Hash) appears in this file or in any signature a consumer touches. Those types live behind the backend, in gitbackend.go.

The protocol adapters are deliberately NOT expressed here. smart_http.go, ssh.go, pack.go and gitexec.go speak the git wire protocol and stream packs through the git CLI; they are git-by-definition and each sits at its own slot. Adding hg or svn means adding a backend beside gitbackend.go plus its own adapter — it does not mean touching a single reader.

ui.go — Hanzo Git's web UI: the browser surface of the embedded, IAM-native git host. Server-rendered HTML in the ONE cloud binary (no separate app, no stock git-host image), reading the SAME org-scoped store + go-git object storage the API/protocol handlers use. This is what lets git.hanzo.ai retire the standalone git web app: repo list, repo home, tree browse, file view, commit log — all native.

Isolation is identical to the rest of git: every page is scoped to the gateway-minted, IAM-VALIDATED X-Org-Id (org(c)); the :org path segment MUST equal the caller's own org, so the UI can never browse another tenant's repos. html/template auto-escaping is the XSS boundary — repo names, paths, and file contents are all rendered through it, never concatenated into HTML.

Routes (browser, distinct from the /v1/git API + smart-HTTP protocol):

GET /git                         the caller's org repo list (home)
GET /git/:org/:repo              repo home: branches, HEAD, root tree, clone
GET /git/:org/:repo/tree/*?ref=  browse a subtree
GET /git/:org/:repo/blob/*?ref=  view a file
GET /git/:org/:repo/commits?ref= commit log

ui_templates.go — the Hanzo Git UI's view layer: data shapes, the render() helper, and the html/template set (chrome + pages). Kept apart from ui.go so the handlers read as flow and the markup lives in one place. All dynamic values pass through html/template auto-escaping — the XSS boundary.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoRepository — the repository does not exist, or has no object store yet.
	ErrNoRepository = errors.New("git: no such repository")
	// ErrNoRevision — the ref or revision does not resolve. An empty repository
	// with no commits answers this too.
	ErrNoRevision = errors.New("git: no such revision")
	// ErrNoPath — the path does not exist at that revision.
	ErrNoPath = errors.New("git: no such path")
	// StopWalk ends a WalkText early without being an error.
	StopWalk = errors.New("git: stop walk")
)

Errors a Repository returns, so handlers can map to HTTP without knowing which backend produced them. Before this, browse.go turned ANY error from resolveRef into 404 "unknown ref", which quietly reported a broken repository as a missing branch.

Functions

func CloneURL added in v1.801.23

func CloneURL(org, name string) string

CloneURL returns the HTTPS smart-HTTP clone URL for an org's repo (https://<domain>/v1/git/<org>/<repo>.git) — the exact URL the git handlers serve. Empty when git is not mounted. The credential is NEVER embedded here; the sandbox presents it out of band (env-fed http.extraHeader), so this URL is safe to log and to hand to a subprocess on argv.

func IndexRepoActivity added in v1.801.23

func IndexRepoActivity(ctx context.Context, in indexInput) error

IndexRepoActivity is the durable index step: read the repo tip's tree from the object plane and fold its text files into the org's code index. Idempotent (full-tree reconcile with prune), so a retry or redelivery re-converges. Exported for worker registration; not called directly.

func IndexRepoWorkflow added in v1.801.23

func IndexRepoWorkflow(ctx workflow.Context, in indexInput) error

IndexRepoWorkflow indexes one repo's pushed tip as a single durable activity, with retry/backoff. Exported for worker registration; not called directly.

func Mount

func Mount(app cloud.Router, deps cloud.Deps) error

Mount wires the git surface onto app per HIP-0106.

func SetIndexer added in v1.801.23

func SetIndexer(fn Indexer)

SetIndexer injects the code-index reactor. The composition root calls it once, after the git and code subsystems both mount. Nil leaves push-index inert.

func ShortRev added in v1.801.245

func ShortRev(r Revision) string

ShortRev is the abbreviated form used for display. It is a projection, never an identifier: pass the full Revision back to the Repository. Seven characters, matching the shortSha the browse API has always emitted.

func Shutdown

func Shutdown() error

Shutdown stops the SSH listener and closes every open store (per-org repo metadata + the SSH key registry). Idempotent.

func VerifyRef added in v1.801.23

func VerifyRef(ctx context.Context, org, repo, branch string) (sha string, ok bool)

VerifyRef reports the tip commit of branch in an org's repo, reading the on-disk bare repo directly (the shared git storage every cloud replica mounts). It is the independent, in-process confirmation that a branch a sandbox claims to have pushed actually LANDED in native git — cloud trusts the branch tips it can read, not the remote runner's self-report. ok is false when git is unmounted, the repo/branch is absent, or the read fails (fail-closed: an unverifiable ref is treated as absent).

Types

type Blob added in v1.801.245

type Blob struct {
	Path      string
	Size      int64
	Content   []byte
	Binary    bool
	Truncated bool
}

Blob is the content of one path at one revision. Binary reports that the bytes are not valid text; Truncated reports that the file exceeded the caller's limit, in which case Content is empty — a large file is offered as a clone, never as megabytes of JSON.

type Change added in v1.801.245

type Change struct {
	Rev         Revision
	Message     string
	AuthorName  string
	AuthorEmail string
	When        time.Time
}

Change is one entry of a revision's history.

type Entry added in v1.801.245

type Entry struct {
	Name string
	Path string
	Dir  bool
	Size int64
	Mode string
}

Entry is one immediate child of a directory in a revision's tree. Dir distinguishes a subtree from a file; Mode is the backend's own permission string (octal for git), carried through for display only.

type IndexedFile added in v1.801.23

type IndexedFile struct {
	Path    string
	Content string
}

IndexedFile is one text file handed across the seam to the code index: its repo-relative path and content.

type Indexer added in v1.801.23

type Indexer func(ctx context.Context, org, billingOrg, project, repo string, files []IndexedFile) error

Indexer folds a pushed repo's text files into the code-intelligence index. Injected at the composition root so the git plane stays free of a clients/code import (the two planes never import each other).

type MirrorTarget added in v1.800.1

type MirrorTarget struct {
	ID        string
	Org       string
	Project   string
	Repo      string
	Host      string
	URL       string
	CreatedAt int64
}

MirrorTarget is a downstream remote a repo's advanced refs are mirrored to (GitHub/GitLab/self). Keyed by (org, repo, host): one target per host per repo.

type Ref added in v1.801.245

type Ref struct {
	Name string
	Rev  Revision
}

Ref is a human-facing name — a branch or a tag — bound to the revision it currently points at.

type Repo

type Repo struct {
	ID            string
	Org           string
	Project       string // may be "" (org-level repo)
	Name          string
	Description   string
	DefaultBranch string
	Public        bool // public repos allow ANONYMOUS read (upload-pack); writes stay org-authed
	SizeBytes     int64
	CreatedAt     int64
	UpdatedAt     int64
}

Repo is the org-scoped, canonical metadata record for one Git repository. Org isolation is the (org, project) pair, enforced at the query layer; the gateway-minted X-Org-Id (HIP-0026) selects the org and X-Project-Id an optional sub-scope. The repo's OBJECTS (packs, refs) live on the billy-backed storage under the same (org, project, name) path — this row is only the metadata + the last-measured storage size that commerce meters on.

type Repository added in v1.801.245

type Repository interface {
	// Refs lists branches and tags, each sorted by name.
	Refs(ctx context.Context) (branches, tags []Ref, err error)

	// Resolve turns a ref name into a revision. An empty name means the
	// repository's own default (HEAD, else the configured default branch). It
	// returns the revision plus the label that was actually used, so a caller
	// can echo "which branch am I looking at" without re-deriving it.
	Resolve(ctx context.Context, ref string) (Revision, string, error)

	// Tree lists the immediate children of dir at rev, directories first then
	// files, each group sorted by name. The root is "".
	Tree(ctx context.Context, rev Revision, dir string) ([]Entry, error)

	// Blob reads one path at rev. A file larger than maxBytes comes back with
	// Truncated set and no content; maxBytes <= 0 means no limit.
	Blob(ctx context.Context, rev Revision, path string, maxBytes int64) (Blob, error)

	// Log walks history from rev, newest first, at most limit entries. A
	// non-empty path restricts the walk to changes touching that path.
	Log(ctx context.Context, rev Revision, path string, limit int) ([]Change, error)

	// DefaultBranch reports the branch the repository points HEAD at.
	DefaultBranch(ctx context.Context) (string, error)

	// WalkText visits every TEXT file in rev's tree. Binary files are skipped —
	// the one consumer is code intelligence, which indexes source, not blobs.
	// A file larger than maxFileBytes is skipped WITHOUT being read, so a huge
	// blob never lands in memory (maxFileBytes <= 0 means no limit); this is why
	// the cap belongs here and not in the callback. Returning an error from fn
	// stops the walk and surfaces that error; returning StopWalk stops it cleanly.
	WalkText(ctx context.Context, rev Revision, maxFileBytes int64, fn func(path, content string) error) error
}

The read model. Every method is safe to call on an empty repository: an unborn tree answers ErrNoRevision rather than panicking, which is what lets Refs report an empty-but-valid repo instead of a 500.

type Revision added in v1.801.245

type Revision string

Revision identifies one immutable state of a Repository. It is OPAQUE: consumers pass it back to the Repository that produced it and never parse it. The git backend fills it with a commit sha; that is an implementation detail and the reason this is a distinct type rather than a bare string.

func (Revision) String added in v1.801.245

func (r Revision) String() string

String renders a revision for display and for JSON. Callers that want a short form use ShortRev, which is display-only and must never be fed back as input.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is one org's repo-metadata database — ONE SQLite file per org at {DataDir}/orgs/{orgSlug}/git.db (opened via cloud.OrgDB). git is org-scoped, not project-scoped: /v1/git/usage is a deliberate org-wide rollup across every project, so the physical boundary is the org and the (optional) project is a row column. MaxOpenConns(1) serializes writes against the file lock.

func (*Store) ClearConflict added in v1.801.23

func (s *Store) ClearConflict(ctx context.Context, org, project, repo, branch string) error

ClearConflict removes one branch's divergence marker — a later ff-apply reconciled it. Idempotent (no row ⇒ no-op).

func (*Store) ClearRepoConflicts added in v1.801.23

func (s *Store) ClearRepoConflicts(ctx context.Context, org, project, repo string) error

ClearRepoConflicts removes every branch's divergence marker for a repo — a full re-import force-fetches every ref, reconciling the repo wholesale. Idempotent.

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database.

func (*Store) ConflictRepoSet added in v1.801.23

func (s *Store) ConflictRepoSet(ctx context.Context, org, project string) (map[string]bool, error)

ConflictRepoSet returns the set of repos (by name) with ≥1 unresolved inbound conflict in (org, project) — one query backing the repo-list status roll-up.

func (*Store) Create

func (s *Store) Create(ctx context.Context, r Repo) error

Create inserts a new repo row. Returns errConflict when (org,project,name) already exists in the org.

func (*Store) CreateMirror added in v1.800.1

func (s *Store) CreateMirror(ctx context.Context, v MirrorTarget) error

CreateMirror inserts a mirror target. errConflict when (org,repo,host) exists.

func (*Store) CreateSubscription added in v1.800.1

func (s *Store) CreateSubscription(ctx context.Context, v Subscription) error

CreateSubscription inserts a subscription. errConflict when (org,repo,channel) already exists — one repo can subscribe a given channel exactly once.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, org, project, name string) (bool, error)

Delete removes a repo row AND cascade-deletes its lifecycle config (subscriptions + mirror targets) in one transaction, so a deleted repo can never leave an orphaned external mirror target that a re-created repo of the same name would silently inherit (Red MED-3: exfil-on-recreate). Reports whether the repo row went.

func (*Store) DeleteMirror added in v1.800.1

func (s *Store) DeleteMirror(ctx context.Context, org, project, repo, id string) (bool, error)

DeleteMirror removes a mirror target by (org, project, repo, id). Reports whether a row went.

func (*Store) DeleteSubscription added in v1.800.1

func (s *Store) DeleteSubscription(ctx context.Context, org, project, repo, id string) (bool, error)

DeleteSubscription removes a subscription by (org, project, repo, id) — a caller may only delete their own org's subscription of the named repo IN SCOPE. Reports whether a row went.

func (*Store) Get

func (s *Store) Get(ctx context.Context, org, project, name string) (Repo, error)

Get returns the repo for (org,project,name) or errNotFound.

func (*Store) List

func (s *Store) List(ctx context.Context, org, project string) ([]Repo, error)

List returns every repo for (org,project), most-recently-updated first.

func (*Store) ListMirrors added in v1.800.1

func (s *Store) ListMirrors(ctx context.Context, org, project, repo string) ([]MirrorTarget, error)

ListMirrors returns every mirror target for the repo (org, project, repo), newest first.

func (*Store) ListOrg

func (s *Store) ListOrg(ctx context.Context, org string) ([]Repo, error)

ListOrg returns every repo across ALL projects for org (usage rollup), most-recently-updated first.

func (*Store) ListPublic added in v1.801.218

func (s *Store) ListPublic(ctx context.Context, org string) ([]Repo, error)

ListPublic returns every PUBLIC repo across all projects for org, newest first — the per-org half of the anonymous explore/discovery surface.

func (*Store) ListSubscriptions added in v1.800.1

func (s *Store) ListSubscriptions(ctx context.Context, org, project, repo string) ([]Subscription, error)

ListSubscriptions returns every subscription for the repo (org, project, repo), newest first.

func (*Store) RecordConflict added in v1.801.23

func (s *Store) RecordConflict(ctx context.Context, org, project, repo, branch, detail string, at int64) error

RecordConflict upserts the divergence marker for one branch: the upstream push could not fast-forward native, so native was preserved and this row records the split-brain for the console + operator. Upsert (not insert) so a repeated diverging push refreshes the detail/timestamp instead of erroring.

func (*Store) SetPublic added in v1.801.37

func (s *Store) SetPublic(ctx context.Context, org, project, name string, public bool, updatedAt int64) error

SetPublic flips a repo's visibility and bumps updated_at. Public grants ANONYMOUS READ (upload-pack) only — receive-pack stays org-authed always.

func (*Store) SetSize

func (s *Store) SetSize(ctx context.Context, org, project, name string, sizeBytes, updatedAt int64) error

SetSize records the last-measured storage size for a repo and bumps updated_at. Called on create and after each push, so the metered number is always the real on-disk size, never a fabricated rollup.

type Subscription added in v1.800.1

type Subscription struct {
	ID        string
	Org       string
	Project   string
	Repo      string
	Channel   string
	Events    string
	CreatedAt int64
}

Subscription binds a repo (by org+name) to a Slack channel for lifecycle notifications. Events is a CSV of LifecycleKind wire names; "" means every supported kind. Project is the scope it was created in (display only) — routing keys on (org, repo).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL