Practical Patterns
Git LFS Basics
type-git provides built-in support for Git LFS (Large File Storage).
Basic Operations
import { TypeGit } from 'type-git/node';
const git = new TypeGit();const repo = await git.open('./repo');
// Pull LFS objectsawait repo.lfs.pull();
// Push LFS objectsawait repo.lfs.push();
// Check LFS statusconst status = await repo.lfs.status();console.log(status.files);LFS with Options
// Pull specific filesawait repo.lfs.pull({ include: ['*.psd', '*.ai'], exclude: ['archive/*'],});
// Push to specific remoteawait repo.lfs.push({ remote: 'upstream' });Progress Tracking
Long-running operations support progress callbacks for both Git and LFS operations.
Git Progress
// Clone with progressawait git.clone('https://github.com/user/repo.git', './repo', { onProgress: (progress) => { console.log(`${progress.phase}: ${progress.current}/${progress.total}`); if (progress.percent !== undefined) { console.log(` ${progress.percent}%`); } },});
// Fetch with progressawait repo.fetch({ onProgress: (progress) => { console.log(`${progress.phase}: ${progress.percent}%`); },});LFS Progress
// LFS pull with progressawait repo.lfs.pull({ onLfsProgress: (progress) => { console.log(`${progress.direction}: ${progress.filesCompleted}/${progress.filesTotal}`); console.log(` ${progress.bytesSoFar}/${progress.bytesTotal} bytes`); if (progress.bitrate) { console.log(` ${progress.bitrate}`); } },});Combined Progress
// Clone with both Git and LFS progressawait git.clone('https://github.com/user/repo.git', './repo', { onProgress: (p) => console.log(`Git: ${p.phase}`), onLfsProgress: (p) => console.log(`LFS: ${p.percent}%`),});Abort Control
Cancel long-running operations using the standard AbortController API.
Basic Usage
const controller = new AbortController();
// Cancel after 30 secondsconst timeout = setTimeout(() => controller.abort(), 30000);
try { await git.clone('https://github.com/user/repo.git', './repo', { signal: controller.signal, }); clearTimeout(timeout);} catch (error) { if (error.kind === 'Aborted') { console.log('Clone was cancelled'); }}User-Initiated Cancel
const controller = new AbortController();
// UI cancel buttoncancelButton.onclick = () => controller.abort();
await repo.fetch({ signal: controller.signal });Cleanup on Abort
By default, type-git cleans up partially created directories when a clone is aborted:
// Cleanup is enabled by defaultawait git.clone(url, './repo', { signal });
// Disable cleanup if neededawait git.clone(url, './repo', { signal, cleanupOnAbort: false,});Error Handling
type-git provides structured error information through the GitError class.
GitError Structure
import { GitError } from 'type-git';
try { await repo.checkout('nonexistent-branch');} catch (error) { if (error instanceof GitError) { console.log('Kind:', error.kind); // 'NonZeroExit' | 'Aborted' | 'SpawnFailed' console.log('Message:', error.message); console.log('Exit code:', error.exitCode); console.log('stderr:', error.stderr); console.log('Category:', error.category); // Semantic error category }}Error Categories
The category property provides semantic classification of errors:
try { await repo.push();} catch (error) { if (error instanceof GitError) { switch (error.category) { case 'authentication': console.log('Authentication failed - check credentials'); break; case 'network': console.log('Network error - check connection'); break; case 'conflict': console.log('Merge conflict detected'); break; case 'not_found': console.log('Reference not found'); break; default: console.log('Git error:', error.message); } }}Available Categories
| Category | Description |
|---|---|
authentication | Auth failures, invalid credentials |
network | Connection issues, timeouts |
conflict | Merge/rebase conflicts |
not_found | Missing refs, files, or repos |
permission | File system permission errors |
locked | Resource locked by another process |
dirty | Uncommitted changes blocking operation |
unknown | Unclassified errors |
Advanced LFS Patterns
For large repositories, you may want more control over when LFS objects are transferred.
2-Phase Commit (Pre-Upload)
Upload LFS objects before pushing refs for better reliability:
// Phase 1: Stage and commit locallyawait repo.add(['large-file.psd']);await repo.commit({ message: 'Add large file' });
// Phase 2: Upload LFS objects firstconst result = await repo.lfsExtra.preUpload({ onLfsProgress: (p) => { console.log(`Uploading: ${p.percent}%`); },});console.log(`Uploaded ${result.uploadedCount} objects (${result.uploadedBytes} bytes)`);
// Phase 3: Push refs (fast, LFS already uploaded)await repo.push();2-Phase Fetch (Pre-Download)
Download LFS objects before checkout for controlled large file management:
// Phase 1: Fetch refs onlyawait repo.fetch();
// Phase 2: Pre-download LFS objects for target branchconst result = await repo.lfsExtra.preDownload({ ref: 'origin/feature-branch', onLfsProgress: (p) => { console.log(`Downloading: ${p.filesCompleted}/${p.filesTotal}`); },});console.log(`Downloaded ${result.downloadedCount} objects`);
// Phase 3: Checkout (fast, LFS already downloaded)await repo.checkout('feature-branch');Batch Size Control
For Windows compatibility or network optimization:
await repo.lfsExtra.preUpload({ batchSize: 25, // Smaller batches for Windows command line limits});