Files
cloudion-labo 2556698dd3 🦀 bions-rust vague 1 : 6 briques build-your-own-x — on ne les rebuild plus jamais
Principe RS-7 : « dès qu'on build un truc, plus personne n'a à le rebuild —
la seule chose à faire est l'optimisation. » (nexus/RepoVerse)
- bion-vc      : horloges vectorielles + MvReg fork-visible (LA spec
                 xion-relativiste-v0 enfin codée — CRDT testé par permutations)
- bion-triplet : l'Adressage Génératif (gen_hash BLAKE3, coords, résidu ;
                 résidu vide quand déjà-su ; align décidable au bit)
- bion-tsoinlog: journal append-only rejouable (CRC32 maison, crash-recovery)
- bion-kv      : magasin clé-valeur bitcask (compaction atomique, tombstones)
- bion-regex   : moteur Thompson NFA linéaire (jamais exponentiel — Russ Cox)
- bion-git     : mini-git content-addressed (SHA-1 maison + vecteurs officiels,
                 branches divergentes = le fork visible)
129 tests verts, clippy 0 warning, doc française = chaque bion est un cours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 01:07:31 +00:00
..

bion-git — mini-git from scratch, le bion du principe « fork = liberté »

Quoi

Le noyau conceptuel de git, réimplémenté depuis les principes en Rust std-only, zéro dépendance, zéro unsafe — même le SHA-1 est maison (src/sha1.rs, ~90 lignes, vérifié contre les vecteurs officiels du NIST) :

  • magasin d'objets content-addressed : blob / tree / commit, nommés par le SHA-1 de leur contenu, stockés dans .bgit/objects/ab/cdef… (2 caractères de répertoire / 38 de fichier, comme git) ;
  • instantanés : write_tree photographie un répertoire, checkout_tree le rematérialise n'importe où ;
  • histoire : commits chaînés (0, 1 ou N parents — le merge est représentable), log en remontant le premier parent ;
  • branches : 41 octets dans refs/heads/<nom> — forker est gratuit.

Les ids de blobs et trees sont bit-à-bit ceux du vrai git (testé contre git hash-object et git write-tree, tri des entrées compris).

Pourquoi

C'est le principe RS-7 fait structure de données : « dès qu'on build un truc, plus personne n'a à le rebuild — des blocs, la seule chose à faire est l'optimisation ». Le content-addressing garantit exactement ça : un contenu déjà construit porte un nom absolu, universel, immuable — le rebuild est impossible par construction, on ne peut que référencer ou optimiser.

Le lien avec le xerboxion : une branche est un chemin dans l'espace des états ; un fork une bifurcation visible. Deux branches divergentes partagent tout leur passé commun sans copier un octet — la divergence n'écrase rien, ne cache rien : elle existe dans le graphe, on peut la montrer, la comparer, la refermer par un merge commit tracé. C'est la sémantique gelée par RS-7 (« divergence = branche, jamais d'écrasement silencieux » — voir bion-vc pour son pendant causal/CRDT) et le socle du nexus/RepoVerse : contribution = repo, reprise = fork, réplication = pull des ids manquants.

Exemple

use bion_git::Repo;

let repo = Repo::init(dir)?;                                  // .bgit/
let tree = repo.write_tree(dir)?;                             // photographier
let racine = repo.commit(tree, &[], "premier instant", "rs-1")?;
repo.branch("main", racine)?;
repo.branch("fork", racine)?;                                 // forker = 41 octets

// diverger…
let cm = repo.commit(tree2, &[racine], "chemin main", "rs-1")?;
let cf = repo.commit(tree3, &[racine], "bifurcation", "rs-7")?;
repo.branch("main", cm)?;
repo.branch("fork", cf)?;

for c in repo.log(repo.branch_target("fork")?)? {             // l'histoire
    println!("{} {}{}", c.id, c.author, c.message);
}
repo.checkout_tree(&tree, dest)?;                             // rematérialiser

API complète : Repo::{init, open, hash_object, cat_object, write_tree, read_tree, checkout_tree, commit, commit_at, read_commit, log, branch, branch_target, branches} + Id, Kind, TreeEntry, Commit, sha1::{sha1, to_hex}. Cette API est stable pour toujours (dogme des bions) : on peut lui ajouter, jamais lui retirer.

Écarts assumés avec le vrai git

Écart Pourquoi
Objets non compressés (pas de zlib) std-only et lisible ; git compresse en deflate après le hash, donc les ids restent identiques — seul l'octet sur disque diffère. C'est LE point d'optimisation invité (voir plus bas).
Commits : auteur = chaîne libre, fuseau figé +0000, committer = copie d'author même format textuel que git, mais sans imposer Nom <email> ; les ids de commits ne coïncident avec git que si on reproduit son format exact
Pas d'index/staging write_tree photographie le répertoire directement
Pas de packfiles, refs non packées un objet = un fichier, un ref = un fichier
Modes 100644 et 40000 seulement ni exécutables ni symlinks (refus explicite)
log = premier parent le graphe complet est dans Commit::parents, à l'appelant d'explorer

build-your-own-x

Correspond au chapitre « Build your own Git » de codecrafters-io/build-your-own-x :

  • Write yourself a Git! (thblt) — la référence dont ce bion suit le périmètre ;
  • Git Internals — Plumbing and Porcelain (Pro Git, ch. 10) — le format d'objets ;
  • CodeCrafters « Build your own Git » — mêmes étapes (init, hash-object, cat-file, write-tree, commit-tree).

Et pour le SHA-1 : FIPS 180-1 (NIST, 1995) — l'implémentation suit la spec pas à pas, commentée en français.

Comment l'optimiser (l'invitation au fork)

Le contrat est l'API + le format d'objets ; tout le reste est forkable :

  1. zlib/deflate : compresser les objets à l'écriture (ids inchangés !) — c'est l'écart n°1 avec git, et un « build your own zlib » pédagogique en soi ;
  2. packfiles + delta-encoding : regrouper N objets en un fichier, encoder les versions successives en deltas — le vrai gain d'espace de git ;
  3. SHA-256 : brancher un second hash (git fait sa propre migration) ;
  4. index/staging : un cache (chemin, mtime, id) pour ne pas re-hasher les fichiers inchangés à chaque write_tree ;
  5. transport : pull(remote) = énumérer les ids manquants et les copier — la réplication pull/apply du xerboxion tombe naturellement du content-addressing ;
  6. merge de trees : diff3 entre deux trees et leur ancêtre commun, avec conflits visibles (jamais d'arbitrage silencieux — brancher bion-vc).

Tests

cargo test -p bion-git — 15 tests unitaires + 2 doc-tests : vecteurs SHA-1 officiels (dont le million de « a »), ids identiques au vrai git (blobs, tree vide, tree imbriqué vérifié contre git write-tree), roundtrips blob/tree/commit, log d'une chaîne, fork de deux branches divergentes depuis un parent commun, merge à deux parents, détection de corruption (le magasin est auto-vérifiant), refus des traversées de chemin et de l'injection dans le format commit.