実践パターン
Git LFSの基本
type-gitはGit LFS(Large File Storage)をビルトインでサポートしています。
基本操作
import { TypeGit } from 'type-git/node';
const git = new TypeGit();const repo = await git.open('./repo');
// LFSオブジェクトをプルawait repo.lfs.pull();
// LFSオブジェクトをプッシュawait repo.lfs.push();
// LFSステータスを確認const status = await repo.lfs.status();console.log(status.files);オプション付きLFS
// 特定のファイルをプルawait repo.lfs.pull({ include: ['*.psd', '*.ai'], exclude: ['archive/*'],});
// 特定のリモートにプッシュawait repo.lfs.push({ remote: 'upstream' });進捗トラッキング
長時間実行される操作は、GitとLFSの両方で進捗コールバックをサポートしています。
Gitの進捗
// クローン時の進捗await 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}%`); } },});
// フェッチ時の進捗await repo.fetch({ onProgress: (progress) => { console.log(`${progress.phase}: ${progress.percent}%`); },});LFSの進捗
// LFSプル時の進捗await 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}`); } },});複合進捗
// GitとLFS両方の進捗を取得await git.clone('https://github.com/user/repo.git', './repo', { onProgress: (p) => console.log(`Git: ${p.phase}`), onLfsProgress: (p) => console.log(`LFS: ${p.percent}%`),});中断制御
標準のAbortController APIを使用して長時間実行される操作をキャンセルできます。
基本的な使い方
const controller = new AbortController();
// 30秒後にキャンセルconst 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('クローンがキャンセルされました'); }}ユーザー操作によるキャンセル
const controller = new AbortController();
// UIのキャンセルボタンcancelButton.onclick = () => controller.abort();
await repo.fetch({ signal: controller.signal });中断時のクリーンアップ
デフォルトでは、クローンが中断された場合、部分的に作成されたディレクトリはクリーンアップされます:
// クリーンアップはデフォルトで有効await git.clone(url, './repo', { signal });
// 必要に応じてクリーンアップを無効化await git.clone(url, './repo', { signal, cleanupOnAbort: false,});エラーハンドリング
type-gitはGitErrorクラスを通じて構造化されたエラー情報を提供します。
GitErrorの構造
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); // セマンティックなエラーカテゴリ }}エラーカテゴリ
categoryプロパティはエラーのセマンティックな分類を提供します:
try { await repo.push();} catch (error) { if (error instanceof GitError) { switch (error.category) { case 'authentication': console.log('認証失敗 - 資格情報を確認してください'); break; case 'network': console.log('ネットワークエラー - 接続を確認してください'); break; case 'conflict': console.log('マージコンフリクトが発生しました'); break; case 'not_found': console.log('参照が見つかりません'); break; default: console.log('Gitエラー:', error.message); } }}利用可能なカテゴリ
| カテゴリ | 説明 |
|---|---|
authentication | 認証失敗、無効な資格情報 |
network | 接続問題、タイムアウト |
conflict | マージ/リベースのコンフリクト |
not_found | 参照、ファイル、リポジトリが見つからない |
permission | ファイルシステムの権限エラー |
locked | 他のプロセスによるリソースロック |
dirty | コミットされていない変更が操作をブロック |
unknown | 未分類のエラー |
高度なLFSパターン
大規模なリポジトリでは、LFSオブジェクトの転送タイミングをより細かく制御したい場合があります。
2フェーズコミット(プリアップロード)
信頼性向上のため、refのプッシュ前にLFSオブジェクトをアップロード:
// フェーズ1: ローカルでステージングとコミットawait repo.add(['large-file.psd']);await repo.commit({ message: '大きなファイルを追加' });
// フェーズ2: まずLFSオブジェクトをアップロードconst result = await repo.lfsExtra.preUpload({ onLfsProgress: (p) => { console.log(`アップロード中: ${p.percent}%`); },});console.log(`${result.uploadedCount}個のオブジェクトをアップロード (${result.uploadedBytes} bytes)`);
// フェーズ3: refをプッシュ(高速、LFSは既にアップロード済み)await repo.push();2フェーズフェッチ(プリダウンロード)
大きなファイルの管理を制御するため、チェックアウト前にLFSオブジェクトをダウンロード:
// フェーズ1: refのみフェッチawait repo.fetch();
// フェーズ2: ターゲットブランチのLFSオブジェクトを事前ダウンロードconst result = await repo.lfsExtra.preDownload({ ref: 'origin/feature-branch', onLfsProgress: (p) => { console.log(`ダウンロード中: ${p.filesCompleted}/${p.filesTotal}`); },});console.log(`${result.downloadedCount}個のオブジェクトをダウンロード`);
// フェーズ3: チェックアウト(高速、LFSは既にダウンロード済み)await repo.checkout('feature-branch');バッチサイズの制御
Windows互換性やネットワーク最適化のため:
await repo.lfsExtra.preUpload({ batchSize: 25, // Windowsコマンドライン制限に対応した小さなバッチ});