Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Git, freebased: pure CAS that’ll knock your SHAs off. LFS hates this repo!

License

Notifications You must be signed in to change notification settings

git-stunts/git-cas

Repository files navigation

@git-stunts/git-cas

git-cas

JESSIE, STOP—

Hold on. He’s turning Git into a blob store. Let him cook.

Most potent clone available on GitHub (legally).

Git, freebased: pure CAS that’ll knock your SHAs off. LFS hates this repo.

Git isn’t source control. Git is a content-addressed object database.
We use the object database.

git-cas chunks files into Git blobs (dedupe for free), optionally encrypts them, and emits a manifest + a real Git tree so you can commit/tag/ref it like any other artifact.

What you get

  • Dedupe for free Git already hashes objects. We just lean into it.
  • Chunked storage big files become stable, reusable blobs.
  • Optional AES-256-GCM encryption store secrets without leaking plaintext into the ODB.
  • Compression gzip before encryption — smaller blobs, same round-trip.
  • Passphrase encryption derive keys from passphrases via PBKDF2 or scrypt — no raw key management.
  • Merkle manifests large files auto-split into sub-manifests for scalability.
  • Manifests a tiny explicit index of chunks + metadata (JSON/CBOR).
  • Tree output generates standard Git trees so assets snap into commits cleanly.
  • Full round-trip store, tree, and restore — get your bytes back, verified.
  • Lifecycle management readManifest, deleteAsset, findOrphanedChunks — inspect trees, plan deletions, audit storage.
  • Vault GC-safe ref-based storage. One ref (refs/cas/vault) indexes all assets by slug. No more silent data loss from git gc.

Use it for: binary assets, build artifacts, model weights, data packs, secret bundles, weird experiments, etc.

git-cas demo

What's new in v2.0.0

Compressioncompression: { algorithm: 'gzip' } on store(). Compression runs before encryption. Decompression on restore() is automatic.

Passphrase-based encryption — Pass passphrase instead of encryptionKey. Keys are derived via PBKDF2 (default) or scrypt. KDF parameters are stored in the manifest for deterministic re-derivation. Use deriveKey() directly for manual control.

Merkle tree manifests — When chunk count exceeds merkleThreshold (default: 1000), manifests are automatically split into sub-manifests stored as separate blobs. readManifest() transparently reconstitutes them. Full backward compatibility with v1 manifests.

See CHANGELOG.md for the full list of changes.

What's new in v3.0.0

Vault — GC-safe ref-based storage. A single Git ref (refs/cas/vault) indexes all stored assets by slug, so git gc can no longer silently discard your data. Initialize with vault init, store with --tree, restore by --slug.

CLI breaking changegit cas restore no longer takes a positional <tree-oid> argument. Use --oid <tree-oid> or --slug <slug> instead.

See CHANGELOG.md for the full list of changes.

Install

npm install @git-stunts/git-cas
npx jsr add @git-stunts/git-cas

Usage (Node API)

import GitPlumbing from '@git-stunts/plumbing';
import ContentAddressableStore from '@git-stunts/cas';
const git = new GitPlumbing({ cwd: './assets-repo' });
const cas = new ContentAddressableStore({ plumbing: git });
// Store a file -> returns a manifest (chunk list + metadata)
const manifest = await cas.storeFile({
 filePath: './image.png',
 slug: 'my-image',
 encryptionKey: myKeyBuffer, // optional (32 bytes)
});
// Turn the manifest into a Git tree OID
const treeOid = await cas.createTree({ manifest });
// Restore later — get your bytes back, integrity-verified
await cas.restoreFile({ manifest, outputPath: './restored.png' });
// Read the manifest back from a tree OID
const m = await cas.readManifest({ treeOid });
// Lifecycle: inspect deletion impact, find orphaned chunks
const { slug, chunksOrphaned } = await cas.deleteAsset({ treeOid });
const { referenced, total } = await cas.findOrphanedChunks({ treeOids: [treeOid] });
// v2.0.0: Compressed + passphrase-encrypted store
const manifest2 = await cas.storeFile({
 filePath: './image.png',
 slug: 'my-image',
 passphrase: 'my secret passphrase',
 compression: { algorithm: 'gzip' },
});

CLI (git plugin)

git-cas installs as a Git subcommand:

# Store a file — prints manifest JSON
git cas store ./image.png --slug my-image
# Store and vault the tree OID (GC-safe)
git cas store ./image.png --slug my-image --tree
# Restore from a vault slug
git cas restore --slug my-image --out ./restored.png
# Restore from a direct tree OID
git cas restore --oid <tree-oid> --out ./restored.png
# Vault management
git cas vault init
git cas vault list
git cas vault info my-image
git cas vault remove my-image
git cas vault history
# Encrypted vault round-trip (passphrase via env var or --vault-passphrase flag)
export GIT_CAS_PASSPHRASE="secret"
git cas vault init
git cas store ./secret.bin --slug vault-entry --tree
git cas restore --slug vault-entry --out ./decrypted.bin

Why not Git LFS?

Because sometimes you want the Git object database to be the store:

  • deterministic
  • content-addressed
  • locally replicable
  • commit-addressable

Also because LFS is, well... LFS.


THIS HASH’LL KNOCK YOUR SHAs OFF! FIRST COMMIT’S FREE, MAN.

dhtux

License

Apache-2.0 Copyright © 2026 James Ross


Built by FLYING ROBOTS

AltStyle によって変換されたページ (->オリジナル) /