Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

@catmint-fs/git

Programmatic git operations built on @catmint-fs/core layers. Implements git plumbing and porcelain in pure TypeScript with no native dependencies, producing repositories that are fully compatible with the canonical git CLI.

Features

  • Pure TypeScript -- no shelling out to git, no native bindings
  • Browser-compatible -- uses Web Crypto for SHA-1, Uint8Array for binary data, fetch() for HTTP transport
  • Adapter-agnostic -- works with any @catmint-fs/core adapter (in-memory, local disk, SQLite, custom)
  • Git-CLI compatible -- repositories created by this library are readable by git log, git status, git branch, etc., and vice versa
  • Full lifecycle -- init, commit, log, branch, checkout, merge (with conflict detection), tag, stash, diff, reset, remote, fetch, push, pull, clone

Installation

pnpm add @catmint-fs/git @catmint-fs/core

Quick start

import { createLayer } from "@catmint-fs/core";
import { initRepository } from "@catmint-fs/git";

const layer = await createLayer({ root: "/tmp/my-repo" });
const repo = await initRepository(layer);

// Create and commit a file
await layer.writeFile("/hello.txt", "Hello, world!\n");
await repo.add("/hello.txt");
const oid = await repo.commit({
  message: "initial commit",
  author: { name: "Alice", email: "alice@example.com" },
});

// Read the log
const commits = await repo.log();
console.log(commits[0].message); // "initial commit"

API

Factory functions

// Initialize a new repository
initRepository(layer: Layer, options?: InitOptions): Promise<Repository>

// Open an existing repository
openRepository(layer: Layer): Promise<Repository>

// Clone a remote repository
cloneRepository(layer: Layer, options: CloneOptions): Promise<Repository>

// Create an HTTP transport
httpTransport(options?: HttpTransportOptions): HttpTransport

Repository

Branching

repo.currentBranch(): Promise<string | null>
repo.createBranch(name, options?): Promise<void>
repo.deleteBranch(name, options?): Promise<void>
repo.listBranches(options?): Promise<BranchInfo[]>
repo.renameBranch(oldName, newName): Promise<void>
repo.checkout(ref, options?): Promise<void>

Staging and status

repo.add(pathOrPaths): Promise<void>
repo.unstage(pathOrPaths): Promise<void>
repo.remove(pathOrPaths, options?): Promise<void>
repo.status(path?): Promise<StatusEntry[]>
repo.listFiles(): Promise<string[]>
repo.isIgnored(path): Promise<boolean>

Commits and history

repo.commit(options): Promise<string>        // returns commit OID
repo.log(options?): Promise<CommitInfo[]>
repo.readCommit(oid): Promise<CommitInfo>

Merging

repo.merge(ref, options?): Promise<MergeResult>
repo.abortMerge(): Promise<void>

merge() supports fast-forward, merge commits, and conflict detection. When conflicts arise, the result contains conflict markers and the conflicted paths.

Tags

repo.createTag(name, options?): Promise<void>   // lightweight or annotated
repo.deleteTag(name): Promise<void>
repo.listTags(): Promise<TagInfo[]>

Diff

repo.diff(options?): Promise<DiffResult>

By default, diffs the working tree against the index. Pass { staged: true } to diff the index against HEAD.

Stash

repo.stash(options?): Promise<void>
repo.listStashes(): Promise<StashEntry[]>
repo.applyStash(options?): Promise<void>
repo.popStash(options?): Promise<void>
repo.dropStash(index?): Promise<void>

Reset

repo.reset(ref, options?): Promise<void>

Supports soft, mixed (default), and hard modes, as well as path-specific resets.

Remotes, fetch, push, pull

repo.addRemote(name, url): Promise<void>
repo.listRemotes(): Promise<RemoteInfo[]>
repo.deleteRemote(name): Promise<void>
repo.setUpstream(branch, upstream): Promise<void>

repo.fetch(remote, options?): Promise<FetchResult>
repo.push(remote, options?): Promise<PushResult>
repo.pull(remote, options?): Promise<MergeResult>

Config

repo.getConfig(key): Promise<string | null>
repo.setConfig(key, value): Promise<void>
repo.deleteConfig(key): Promise<void>

Refs

repo.resolveRef(ref): Promise<string>          // returns OID
repo.listRefs(prefix?): Promise<RefEntry[]>

Lower-level modules

For advanced use cases, the internals are also exported:

Export Description
ObjectDB Read/write loose git objects (blobs, trees, commits, tags)
RefStore Manage loose refs, symbolic refs, and packed-refs
IndexFile Parse and serialize the git index (binary format v2)
GitConfig Read/write git config files
GitIgnore Evaluate .gitignore patterns
DiffEngine Compute file-level and hunk-level diffs
MergeEngine Three-way merge with conflict detection
StashManager Stash save/apply/pop/drop operations
HttpTransport Smart HTTP transport for fetch/push
computeDiffHunks Standalone function for line-level diff computation

Using with SQLite

import { createLayer } from "@catmint-fs/core";
import { SqliteAdapter } from "@catmint-fs/sqlite-adapter";
import { initRepository } from "@catmint-fs/git";

const adapter = new SqliteAdapter({ database: ":memory:" });
const layer = await createLayer({ root: "/", adapter });

const repo = await initRepository(layer);
// ... use repo normally

Git CLI compatibility

Repositories produced by this library are valid git repositories. You can verify with the standard git CLI:

cd /tmp/my-repo
git log --oneline
git status
git branch -a
git tag -l

Conversely, repositories created by the git CLI can be opened with openRepository().

License

GPL-2.0 -- see LICENSE for details.