Local-only TypeScript Git implementation with pluggable filesystem support
TS-Git is a pure TypeScript implementation of Git that runs entirely in the browser or Node.js environment. It provides a Git-compatible API with pluggable filesystem adapters, allowing you to work with Git repositories using various storage backends.
- π§ Pluggable Filesystem - Works with in-memory, browser storage, or native filesystems
- π¦ Zero Dependencies - Lightweight implementation with minimal external dependencies
- π§ͺ Well Tested - Comprehensive test suite with 470+ tests
- π Browser Native - Run Git operations directly in the browser
- πͺ Type Safe - Fully typed with TypeScript
npm install @keydown-app/ts-gitThe package also exports an optional embedded terminal command surface as @keydown-app/ts-git/cli (CommandParser, prompts overridable via CommandContext.copy).
import { GitClient, MemoryFSAdapter } from '@keydown-app/ts-git';
// Create a filesystem adapter (in-memory for this example)
const fs = new MemoryFSAdapter();
// Initialize Git client
const git = new GitClient({ fs, dir: '/my-repo' });
// Initialize a repository
await git.init({ defaultBranch: 'main' });
// Stage and commit files
await git.add('README.md');
await git.commit('Initial commit', {
name: 'John Doe',
email: 'john@example.com',
});
// View commit history
const commits = await git.log();| Command | Status | Description |
|---|---|---|
init |
β Supported | Initialize a new Git repository |
add <file> |
β Supported | Stage file(s) for commit |
add -A |
β Supported | Stage all changes |
rm <file> |
β Supported | Remove file(s) from index |
commit -m |
β Supported | Create a new commit |
status |
β Supported | Show working tree status |
log |
β Supported | Show commit history |
branch |
β Supported | List branches |
branch <name> |
β Supported | Create new branch |
branch -d/-D |
β Supported | Delete branch |
checkout <branch> |
β Supported | Switch branches |
reset [file] |
β Supported | Unstage file(s) |
diff |
β Supported | Show changes between commits/index/worktree |
diff --cached |
β Supported | Show staged changes (index vs HEAD) |
diff --name-only |
β Supported | Show only names of changed files |
diff --name-status |
β Supported | Show names and status of changed files |
diff --stat |
β Supported | Show diffstat summary |
These commands provide direct access to Git's underlying object model. They are useful for building advanced tools or implementing custom version control workflows.
| Command | Status | Description |
|---|---|---|
cat-file |
β Supported | Read object content by OID |
cat-file -t |
β Supported | Show object type |
cat-file -p |
β Supported | Pretty-print object content |
hash-object |
β Supported | Hash content and return OID |
hash-object -w |
β Supported | Hash and write to object store |
ls-tree |
β Supported | List tree entries by OID or ref |
ls-tree -r |
β Supported | Recursive tree listing |
update-index |
β Supported | Manually update index entries |
update-index --add |
β Supported | Stage file to index |
update-index --remove |
β Supported | Unstage file from index |
| tag | β Not Supported | Create, list, or delete tags |
| merge | β Not Supported | Join development histories |
| rebase | β Not Supported | Reapply commits on top of another base |
| cherry-pick | β Not Supported | Apply changes from specific commits |
| stash | β Not Supported | Stash changes |
| clone | β Not Supported | Clone a repository |
| fetch | β Not Supported | Download objects from remote |
| pull | β Not Supported | Fetch and merge |
| push | β Not Supported | Update remote refs |
| remote | β Not Supported | Manage tracked repositories |
| config | β Not Supported | Get/set repository options |
| show | β Not Supported | Show various types of objects |
Run the interactive web-based Git terminal:
npm run devThis starts a development server with a terminal interface for testing Git commands.
npm run dev:taurinpm run dev:zenTS-Git supports multiple filesystem adapters:
- MemoryFSAdapter - In-memory storage (great for testing)
- TauriFSAdapter - Native filesystem via Tauri
- ZenFSAdapter - Browser-based persistent storage
- FileSystemAccessAdapter - Native File System Access API
- CustomFSAdapter - Create your own custom filesystem adapter
To create your own filesystem adapter, you can extend the FSAdapter interface and implement the methods. See the examples for more details.
# Install dependencies
pnpm install
# Build all packages
npm run build
# Run tests
npm test
# Type check
npm run typecheck
# Lint
npm run lint
# Format code
npm run formatts-git/
βββ packages/
β βββ ts-git/ # Core Git implementation
β βββ src/
β β βββ commands/ # Git command implementations
β β βββ core/ # Core Git objects (blob, tree, commit)
β β βββ client/ # GitClient wrapper class
β β βββ cli/ # Optional CommandParser (embedded terminal)
β β βββ fs/ # Filesystem adapters
β βββ package.json
β βββ ts-git-ui/ # Web UI example
β βββ src/
β β βββ components/ # Web UI components
β β βββ styles.css # Web UI styles
β β βββ package.json
β βββ ts-git-diff-myers/ # Myers line diff implementation
β βββ src/
β β βββ myers.ts
β β βββ package.json
β βββ ts-git-diff-words/ # Prose/word diff implementation (placeholder)
β βββ src/
β β βββ word.ts
β β βββ package.json
βββ examples/
β βββ with-memory-fs/ # In-memory filesystem example
β βββ with-tauri-fs/ # Desktop app example
β βββ with-zen-fs/ # Browser filesystem example
βββ package.json
Contributions are welcome! This project is in early alpha, so please expect API changes as we stabilize the codebase.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
The diff command is now implemented with the following capabilities:
- Worktree vs Index (
git diff): Shows unstaged changes in tracked files - Index vs HEAD (
git diff --cachedor--staged): Shows staged changes - Commit comparisons (
git diff A B): Shows differences between two commits - Path filtering (
git diff -- <path>): Limits diff to specific paths - Output formats:
- Default unified diff with patch format
--name-only: Lists only changed filenames--name-status: Shows status (A/M/D) and filenames--stat: Shows diffstat summary
Index and status
- Index version 4 is rejected; use Git index version 2 or 3 (e.g.
git config core.indexVersion 3and re-index). - Unmerged (multi-stage) index entries are collapsed to a single representative stage for status and diff (not full
UU/ conflict semantics). - assume-unchanged / skip-worktree flags are parsed from CLI-produced indices but behavior may not match Gitβs status rules in all cases.
The following git diff features are not yet implemented:
- Rename detection (
-M,-C,--find-renames,--find-copies): Files moved or copied appear as separate deletions and additions - Merge-base diffs (
--merge-base,A...Bsyntax): Triple-dot notation treats both sides as regular commits - Binary file handling: Binary files are detected but content diffing is not fully supported
- No-index mode (
--no-index): Comparing paths outside a git repository - Range notation (
A^!,A^@): Special revision range syntaxes - Word diff (
--word-diff): Word-level diffs instead of line-level - Color output: ANSI color codes in diff output
- Config-driven defaults: Respecting
diff.*configuration options
The unified diff output format follows Git's standard conventions:
diff --git a/<path> b/<path>headersindex <oid>..<oid>lines for modified filesnew file mode/deleted file modeindicators--- a/<path>/+++ b/<path>markers (with/dev/nullfor add/delete)- Unified hunk headers with
@@ -l,s +l,s @@ - Context lines prefixed with space, additions with
+, deletions with-
Minor formatting differences from canonical Git output may exist in edge cases.
This project is licensed under the MIT License - see the LICENSE file for details.