Custom Adapters
For special use cases, you can create custom adapters to control how type-git executes git commands and handles file operations.
When to Create Custom Adapters
- Testing with mocked git commands
- Custom process spawning (containers, SSH)
- Custom file system (virtual FS, cloud storage)
- Logging/auditing all git operations
ExecAdapter Interface
interface ExecAdapter { getCapabilities(): Capabilities; spawn(options: SpawnOptions, handlers?: StreamHandler): Promise<SpawnResult>; spawnStreaming?(options: SpawnOptions): SpawnHandle;}
type SpawnOptions = { argv: string[]; env?: Record<string, string>; cwd?: string; signal?: AbortSignal;};
type SpawnResult = { stdout: string; stderr: string; exitCode: number; aborted: boolean;};FsAdapter Interface
interface FsAdapter { createTempFile(prefix?: string): Promise<string>; deleteFile(filePath: string): Promise<void>; deleteDirectory(dirPath: string): Promise<void>; exists(filePath: string): Promise<boolean>; tail(options: TailOptions): Promise<void>; tailStreaming?(filePath: string, options?: TailStreamingOptions): TailHandle;}Example: Logging Adapter
import { createGit, createNodeAdapters } from 'type-git/node';import type { ExecAdapter, SpawnOptions, SpawnResult } from 'type-git';
class LoggingExecAdapter implements ExecAdapter { private inner: ExecAdapter;
constructor(inner: ExecAdapter) { this.inner = inner; }
getCapabilities() { return this.inner.getCapabilities(); }
async spawn(options: SpawnOptions, handlers?: StreamHandler): Promise<SpawnResult> { console.log('[GIT]', options.argv.join(' ')); const start = Date.now();
const result = await this.inner.spawn(options, handlers);
console.log(`[GIT] Completed in ${Date.now() - start}ms (exit: ${result.exitCode})`); return result; }}
// Usageconst nodeAdapters = createNodeAdapters();const git = createGit({ adapters: { exec: new LoggingExecAdapter(nodeAdapters.exec), fs: nodeAdapters.fs, },});Example: Mock Adapter for Testing
class MockExecAdapter implements ExecAdapter { private responses: Map<string, SpawnResult> = new Map();
getCapabilities() { return { runtime: 'node' as const }; }
mockCommand(pattern: string, result: Partial<SpawnResult>) { this.responses.set(pattern, { stdout: result.stdout ?? '', stderr: result.stderr ?? '', exitCode: result.exitCode ?? 0, aborted: false, }); }
async spawn(options: SpawnOptions): Promise<SpawnResult> { const command = options.argv.join(' ');
for (const [pattern, result] of this.responses) { if (command.includes(pattern)) { return result; } }
throw new Error(`Unmocked command: ${command}`); }}
// Usage in testsconst mockExec = new MockExecAdapter();mockExec.mockCommand('--version', { stdout: 'git version 2.40.0' });mockExec.mockCommand('status --porcelain', { stdout: '' });
const git = createGit({ adapters: { exec: mockExec, fs: createMockFsAdapter(), },});Environment Isolation
type-git supports environment isolation for scenarios like:
- Using a custom HOME directory for isolated git config
- Using a specific version of git from a custom path
- Setting up credential helpers
- Running git with custom environment variables
TypeGit Options
The TypeGit class accepts the same options as createGit (except adapters):
import { TypeGit } from 'type-git/node';
// Use isolated HOME for git configconst git = new TypeGit({ home: '/isolated/home',});
// Global config operations will use /isolated/home/.gitconfigawait git.config.set('user.name', 'Test User');await git.config.set('user.email', 'test@example.com');
// Clone using isolated configconst repo = await git.clone('https://github.com/user/repo.git', './repo');Custom Git Binary Path
Use a specific version of git by setting pathPrefix:
const git = new TypeGit({ pathPrefix: ['/opt/git-2.45/bin'], // Prepended to PATH});
const version = await git.version(); // Uses /opt/git-2.45/bin/gitCredential Helper Configuration
Configure credential helpers for authentication:
const git = new TypeGit({ credential: { helper: 'store', // Use git-credential-store },});
// Or with a custom helper pathconst git = new TypeGit({ credential: { helper: 'my-helper', helperPath: '/path/to/git-credential-my-helper', },});Combined Example
import { TypeGit } from 'type-git/node';
// Fully isolated git environmentconst git = new TypeGit({ home: '/app/git-home', // Isolated .gitconfig pathPrefix: ['/app/git/bin'], // Custom git binary env: { GIT_AUTHOR_NAME: 'CI Bot', GIT_AUTHOR_EMAIL: 'ci@example.com', }, credential: { helper: 'store', },});
// All operations use the isolated environmentawait git.config.set('user.name', 'CI Bot');const repo = await git.clone('https://github.com/user/repo.git', './repo');Using createGit
For full control (including custom adapters), use createGit instead of TypeGit:
import { createGit, createNodeAdapters } from 'type-git/node';
const git = createGit({ adapters: createNodeAdapters(), gitBinary: '/custom/path/to/git', env: { GIT_AUTHOR_NAME: 'Custom Author' },});Available Options
| Option | Description |
|---|---|
adapters | Runtime adapters (required for createGit, auto-configured for TypeGit) |
gitBinary | Git executable name (default: 'git') |
env | Additional environment variables |
pathPrefix | Directories to prepend to PATH |
home | Custom HOME directory (also sets USERPROFILE on Windows) |
credential | Credential helper configuration |