- Cargo workspace with 5 sub-crates: alkgit-core (storage), alkgit-transport (smart protocol), alkgit-http, alkgit-ssh, alkgitd (binary); sha1 pinned through the gix stack, sha256 passthrough feature - docs/research/: vision, gitoxide alignment, alk stack fit, server-side protocol inventory, license/reference policy, POC plan - AGENTS.md: conventions mirroring alkcall (no comments, thiserror, tokio, no secrets on wire/at rest, visible-surface=authorized-surface, gitoxide-only serving path, bounded resources, registry-resolved repos) Verified: cargo build, clippy -D warnings, fmt, test, check --all-features
5.4 KiB
Research: gitoxide (gix) as the git engine
Status: initial pass complete
Date: 2026-09-19
Sources: local clone at /workspace/gitoxide (repo HEAD 77c8cd956,
tag-described as gix-transport-v0.59.2-130-g77c8cd956), crates.io API.
TL;DR
gitoxide covers the storage layer (odb, packs, refs, objects, fsck) and gives
us the packetline codec, but it does not give us a git server. gix-protocol
and gix-transport are client-side (fetch/clone from the point of view of the
machine asking for objects). The server half of the smart protocol — capability
advertisement, ls-refs command dispatch, fetch negotiation on the serving side,
pack generation on demand, and receive-pack application with ref transaction and
update-hook semantics — has to be built by us. This is expected and acceptable:
it is exactly the narrow protocol-shim layer our security model wants to own
anyway (see git-protocol.md).
Version alignment (important)
| crate | crates.io max stable | local clone | note |
|---|---|---|---|
| gix | 0.87.1 | 0.87.1 | in sync |
| gix-packetline | 0.22.2 | 0.22.2 | in sync |
| gix-transport | 0.59.2 | 0.59.2 | in sync |
| gix-protocol | 0.65.1 | 0.65.1 | in sync |
| gix-pack | 0.74.2 | 0.74.2 | in sync |
| gix-odb | 0.84.0 | 0.84.0 | in sync |
| gix-ref | 0.67.1 | 0.67.1 | in sync |
| gix-object | 0.64.1 | 0.64.1 | in sync |
| gix-hash | 0.26.2 | 0.26.2 | in sync |
| gix-fsck | 0.25.1 | 0.25.1 | in sync |
The published 0.87.1 (2026-08-24) matches the clone; the clone carries a
handful of unreleased commits on top. Pin published crates.io versions in
our manifests; treat the clone as a reading/reference aid, not a path
dependency. If an unreleased fix turns out to be required, that is an OQ for
architecture (gitoxide git-patch or [patch] section is the fallback).
Hash algorithm gotcha (encountered live)
gix with default-features = false and no hash feature fails to compile:
gix-hash emits compile_error!("Please set either the sha1 or the sha256 feature flag"). The workspace manifest now pins features = ["sha1"]
throughout (gix, gix-pack, gix-odb, gix-object, gix-hash) and our crates carry
a matching sha256 passthrough feature for the future. This is a
compile-time-rejected invariant, so the config can't drift silently.
What we can use off the shelf
Storage (strongest area — use as-is)
gix-odb— object database with loose + packed stores, dynamic multi-index loading,Handlewith caching; thedynamicstore refreshes on mtime changes, which suits a long-running server.gix-pack— pack data reading (index file, multi-index, delta resolution) and pack writing (bundle::write→write_to_directoryfor index-from-stream). Pack writing produces index+pack into a directory; streaming a pack directly to a socket needs evaluation (POC candidate).gix-ref— ref store withtransactionmodule (compare-and-swap semantics, reflog), which is what receive-pack needs for atomic ref updates.gix-object— object parsing/encoding (commit, tree, tag, blob).gix-fsck— connectivity checks for received packs.gix-discover— repository discovery /.gitdir resolution.gixfacade — repo opening, config, etc. For library-developer usage gitoxide recommendsdefault-features = false+ only the components needed; follow that to keep compile times down.
Wire format (use as-is)
gix-packetline— pkt-line encode/decode, both blocking andfutures-ioasync (async-iofeature). This is the one crate both the http and ssh interfaces need most; it is small and stable (0.22.x).gix-transport— definesProtocol(V0/V1/V2),client::MessageKind, and the fetch-side abstractions. Only the types are reusable server-side; its transport implementations (client) are not what we need.
Client side (exists, mostly irrelevant for us)
gix-protocol— handshake,ls-refs, fetch negotiation from the client side (fetch::Response::from_line_readerparses server responses; the negotiate module builds request arguments). Useful as a reference for response shapes we must produce server-side, and possibly reused for alkgit-to-alkgit replication later.gix-transport/src/lib.rsexports onlypub mod client— confirming no server-side half exists upstream.
What gitoxide does NOT give us (we own this)
- Capability advertisement (V0/V1 first-want line and V2 capability handshake) — must produce ourselves.
- Server-side command dispatch —
ls-refs,fetchV2 command parsing and the request→response state machine. - Server-side negotiation — evaluating client haves against our refs (ack/NAK logic, shallow handling on the serve side).
- On-demand pack generation for a fetch — pack writing exists
(
gix-pack bundle::write) but "stream a pack computed from a want/have set to a socket" composition needs a POC; worst case we walk objects ourselves via odb and feedgix-pack::data::output::bytesentries-to-bytes writers. - receive-pack — parsing client pack stream (
gix-pack::data::inputcan parse a pack from a reader), fsck, ref CAS updates viagix-reftransaction, reporting status (unpack ok/nglines).
License
MIT OR Apache-2.0 — same as ours. Clean to depend on and to read for inspiration (attribution not required under either license, though NOTICE-type courtesy is fine).