# @automaker/git-utils Git operations and utilities for AutoMaker. ## Overview This package provides git-related utilities including repository detection, status parsing, and diff generation for both tracked and untracked files. ## Installation ```bash npm install @automaker/git-utils ``` ## Exports ### Repository Detection Check if a path is a git repository. ```typescript import { isGitRepo } from '@automaker/git-utils'; const isRepo = await isGitRepo('/project/path'); if (isRepo) { console.log('This is a git repository'); } ``` ### Status Parsing Parse git status output into structured data. ```typescript import { parseGitStatus } from '@automaker/git-utils'; import type { FileStatus } from '@automaker/git-utils'; const statusOutput = await execAsync('git status --porcelain'); const files: FileStatus[] = parseGitStatus(statusOutput.stdout); files.forEach((file) => { console.log(`${file.statusText}: ${file.path}`); // Example: "Modified: src/index.ts" // Example: "Untracked: new-file.ts" }); ``` ### Diff Generation Generate diffs including untracked files. ```typescript import { generateSyntheticDiffForNewFile, appendUntrackedFileDiffs, getGitRepositoryDiffs, } from '@automaker/git-utils'; // Generate diff for single untracked file const diff = await generateSyntheticDiffForNewFile('/project/path', 'src/new-file.ts'); // Get complete repository diffs (tracked + untracked) const result = await getGitRepositoryDiffs('/project/path'); console.log(result.diff); // Combined diff string console.log(result.files); // Array of FileStatus console.log(result.hasChanges); // Boolean ``` ### Non-Git Directory Support Handle non-git directories by treating all files as new. ```typescript import { listAllFilesInDirectory, generateDiffsForNonGitDirectory } from '@automaker/git-utils'; // List all files (excluding build artifacts) const files = await listAllFilesInDirectory('/project/path'); // Generate diffs for non-git directory const result = await generateDiffsForNonGitDirectory('/project/path'); console.log(result.diff); // Synthetic diffs for all files console.log(result.files); // All files as "New" status ``` ## Types ### FileStatus ```typescript interface FileStatus { status: string; // Git status code (M/A/D/R/C/U/?/!) path: string; // File path relative to repo root statusText: string; // Human-readable status } ``` ### Status Codes - `M` - Modified - `A` - Added - `D` - Deleted - `R` - Renamed - `C` - Copied - `U` - Updated - `?` - Untracked - `!` - Ignored - ` ` - Unmodified ### Status Text Examples - `"Modified"` - File has changes - `"Added"` - New file in staging - `"Deleted"` - File removed - `"Renamed"` - File renamed - `"Untracked"` - New file not in git - `"Modified (staged), Modified (unstaged)"` - Changes in both areas ## Usage Example ```typescript import { isGitRepo, getGitRepositoryDiffs, parseGitStatus } from '@automaker/git-utils'; async function getProjectChanges(projectPath: string) { const isRepo = await isGitRepo(projectPath); if (!isRepo) { console.log('Not a git repository, analyzing all files...'); } const result = await getGitRepositoryDiffs(projectPath); if (!result.hasChanges) { console.log('No changes detected'); return; } console.log(`Found ${result.files.length} changed files:\n`); // Group by status const byStatus = result.files.reduce( (acc, file) => { acc[file.statusText] = acc[file.statusText] || []; acc[file.statusText].push(file.path); return acc; }, {} as Record ); Object.entries(byStatus).forEach(([status, paths]) => { console.log(`${status}:`); paths.forEach((path) => console.log(` - ${path}`)); }); return result.diff; } ``` ## Features ### Binary File Detection Automatically detects binary files by extension and generates appropriate diff markers. **Supported binary extensions:** - Images: `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, etc. - Documents: `.pdf`, `.doc`, `.docx`, etc. - Archives: `.zip`, `.tar`, `.gz`, etc. - Media: `.mp3`, `.mp4`, `.wav`, etc. - Fonts: `.ttf`, `.otf`, `.woff`, etc. ### Large File Handling Files larger than 1MB show size information instead of full content. ### Synthetic Diff Format Generates unified diff format for untracked files: ```diff diff --git a/new-file.ts b/new-file.ts new file mode 100644 index 0000000..0000000 --- /dev/null +++ b/new-file.ts @@ -0,0 +1,10 @@ +export function hello() { + console.log('Hello'); +} ``` ### Directory Filtering When scanning non-git directories, automatically excludes: - `node_modules`, `.git`, `.automaker` - Build outputs: `dist`, `build`, `out`, `tmp`, `.tmp` - Framework caches: `.next`, `.nuxt`, `.cache`, `coverage` - Language-specific: `__pycache__` (Python), `target` (Rust), `vendor` (Go/PHP), `.gradle` (Gradle), `.venv`/`venv` (Python) ## Error Handling Git operations can fail for various reasons. This package provides graceful error handling patterns: ### Common Error Scenarios **1. Repository Not Found** ```typescript const isRepo = await isGitRepo('/path/does/not/exist'); // Returns: false (no exception thrown) ``` **2. Not a Git Repository** ```typescript const result = await getGitRepositoryDiffs('/not/a/git/repo'); // Fallback behavior: treats all files as "new" // Returns synthetic diffs for all files in directory ``` **3. Git Command Failures** ```typescript // Permission errors, corrupted repos, or git not installed try { const result = await getGitRepositoryDiffs('/project'); } catch (error) { // Handle errors from git commands // Errors are logged via @automaker/utils logger console.error('Git operation failed:', error); } ``` **4. File Read Errors** ```typescript // When generating synthetic diffs for inaccessible files const diff = await generateSyntheticDiffForNewFile('/path', 'locked-file.txt'); // Returns placeholder: "[Unable to read file content]" // Error is logged but doesn't throw ``` ### Best Practices 1. **Check repository status first**: ```typescript const isRepo = await isGitRepo(path); if (!isRepo) { // Handle non-git case appropriately } ``` 2. **Expect non-git directories**: - `getGitRepositoryDiffs()` automatically handles both cases - Always returns a valid result structure 3. **Monitor logs**: - Errors are logged with the `[GitUtils]` prefix - Check logs for permission issues or git configuration problems 4. **Handle edge cases**: - Empty repositories (no commits yet) - Detached HEAD states - Corrupted git repositories - Missing git binary ## Dependencies - `@automaker/types` - FileStatus type definition - `@automaker/utils` - Logger utilities ## Used By - `@automaker/server` - Git routes, worktree operations, feature context