Skip to main content

Overview

useGit uses promise-based error handling. All Git operations return promises that:
  • Resolve with the command output (as a string) when successful
  • Reject with an Error object when the command fails

Basic Error Handling

Use standard try/catch blocks to handle errors:
import git from "use-git"

try {
  await git.commit("Update feature")
  console.log("Commit successful")
} catch (error) {
  console.error("Commit failed:", error.message)
}

Error Types

useGit generates two types of errors based on the failure mode:

Command Execution Errors

These occur when the Git command itself cannot be executed (e.g., Git not installed, spawn fails):
try {
  await git.status()
} catch (error) {
  // Error message format:
  // "Error executing command git status: <error details>"
  console.error(error.message)
}
Common causes:
  • Git is not installed
  • Git executable not in PATH
  • Permission issues
  • System resource limits

Command Failure Errors

These occur when Git executes but returns a non-zero exit code:
try {
  await git.commit("Empty commit") // No staged changes
} catch (error) {
  // Error message format:
  // "Git command failed (exit <code>):\n<command>\n<stderr output>"
  console.error(error.message)
}
Common causes:
  • Invalid Git command or options
  • Repository state issues
  • Merge conflicts
  • Authentication failures
  • Pre-commit hooks failing

Error Message Structure

Command Execution Error Format

Error executing command git <command>: <error message>
Example:
Error executing command git status: spawn git ENOENT

Command Failure Error Format

Git command failed (exit <code>):
<command>
<stderr output>
Example:
Git command failed (exit 1):
commit -m Update feature
nothing to commit, working tree clean

Common Error Scenarios

Nothing to Commit

import git from "use-git"

try {
  await git.commit("Update")
} catch (error) {
  if (error.message.includes("nothing to commit")) {
    console.log("No changes to commit")
  } else {
    throw error // Re-throw unexpected errors
  }
}

Not a Git Repository

import { createGit } from "use-git"

const git = createGit({ cwd: "/some/directory" })

try {
  await git.status()
} catch (error) {
  if (error.message.includes("not a git repository")) {
    console.log("Initializing new repository...")
    await git.init()
  } else {
    throw error
  }
}

Merge Conflicts

try {
  await git.merge("feature-branch")
} catch (error) {
  if (error.message.includes("CONFLICT")) {
    console.log("Merge conflicts detected")
    // Get list of conflicted files
    const status = await git.status(["--short"])
    console.log(status)
  } else {
    throw error
  }
}

Authentication Failures

try {
  await git.push()
} catch (error) {
  if (
    error.message.includes("Authentication failed") ||
    error.message.includes("Permission denied")
  ) {
    console.error("Git authentication failed. Check your credentials.")
  } else {
    throw error
  }
}

Safe Operations

For operations where you want to check success/failure without throwing errors, some functions provide “safe” alternatives:
import { runCmdSafe } from "use-git/internal"

// Returns boolean instead of throwing
const success = await runCmdSafe("status", [])

if (success) {
  console.log("Status check passed")
} else {
  console.log("Status check failed")
}
The runCmdSafe function is part of the internal API. It returns true if the command succeeds (exit code 0) and false otherwise, without throwing errors.

Validation Before Operations

Prevent errors by validating repository state first:

Check Repository Exists

import git from "use-git"

if (await git.isRepo()) {
  await git.status()
} else {
  console.log("Not a Git repository")
}

Check for Uncommitted Changes

const isDirty = await git.isDirty()

if (isDirty) {
  console.log("You have uncommitted changes")
  const proceed = await askUser("Continue anyway?")
  
  if (!proceed) {
    process.exit(0)
  }
}

Check for Staged Changes

const hasStagedDiff = await git.hasStagedDiff()

if (!hasStagedDiff) {
  console.log("No staged changes to commit")
} else {
  await git.commit("Update files")
}

Error Recovery Patterns

Retry Logic

async function retryOperation<T>(
  operation: () => Promise<T>,
  maxAttempts = 3,
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await operation()
    } catch (error) {
      if (attempt === maxAttempts) {
        throw error
      }
      console.log(`Attempt ${attempt} failed, retrying...`)
      await new Promise(resolve => setTimeout(resolve, 1000))
    }
  }
  throw new Error("Max attempts reached")
}

// Usage
try {
  await retryOperation(() => git.push())
} catch (error) {
  console.error("Push failed after multiple attempts:", error.message)
}

Graceful Degradation

async function getRepoInfo(repoPath: string) {
  const git = createGit({ cwd: repoPath })
  
  const info = {
    isRepo: false,
    branch: null,
    isDirty: false,
    lastCommit: null,
  }
  
  try {
    info.isRepo = await git.isRepo()
    
    if (info.isRepo) {
      try {
        info.branch = await git.currentBranch()
      } catch {
        // Branch detection failed, continue anyway
      }
      
      try {
        info.isDirty = await git.isDirty()
      } catch {
        // Dirty check failed, continue anyway
      }
    }
  } catch (error) {
    console.warn("Failed to gather full repo info:", error.message)
  }
  
  return info
}

Cleanup on Failure

import { createGit } from "use-git"
import { rm } from "node:fs/promises"

const tempPath = "/tmp/clone-test"
const git = createGit({ cwd: tempPath })

try {
  await git.clone("https://github.com/user/repo.git", tempPath)
  
  // Do something with the cloned repo
  const status = await git.status()
  console.log(status)
} catch (error) {
  console.error("Operation failed:", error.message)
  
  // Cleanup partial clone
  try {
    await rm(tempPath, { recursive: true, force: true })
  } catch {
    // Cleanup failed, but don't throw
    console.warn("Failed to cleanup temporary directory")
  }
  
  throw error
} finally {
  // Always log completion
  console.log("Operation completed")
}

Debug Mode for Troubleshooting

Enable debug mode to see exactly what Git commands are being executed:
import { createGit } from "use-git"

const git = createGit({ debug: true })

try {
  await git.commit("Update")
} catch (error) {
  // Debug output will show:
  // [use-git] DEBUG  running: git commit -m Update
  console.error(error.message)
}
Debug mode is invaluable for understanding why commands fail. It shows the exact command being executed, making it easy to reproduce issues manually.

Type-Safe Error Handling

For TypeScript users, ensure proper error typing:
import git from "use-git"

try {
  await git.commit("Update")
} catch (error) {
  // Type guard for Error objects
  if (error instanceof Error) {
    console.error(error.message)
    
    // Access error properties safely
    if (error.stack) {
      console.debug(error.stack)
    }
  } else {
    // Handle non-Error throws
    console.error("Unknown error:", error)
  }
}

Best Practices

Always Handle Errors

// Bad: Unhandled rejection
await git.commit("Update")

// Good: Explicit error handling
try {
  await git.commit("Update")
} catch (error) {
  handleError(error)
}

Provide Context in Error Messages

try {
  await git.push()
} catch (error) {
  throw new Error(
    `Failed to push changes to remote: ${error.message}`
  )
}

Don’t Swallow Errors

// Bad: Silent failure
try {
  await git.commit("Update")
} catch {
  // Error ignored
}

// Good: Log or re-throw
try {
  await git.commit("Update")
} catch (error) {
  console.error("Commit failed:", error)
  throw error // Or handle appropriately
}

Use Specific Error Checks

// Bad: Generic error handling
try {
  await git.commit("Update")
} catch (error) {
  console.log("Something went wrong")
}

// Good: Specific error identification
try {
  await git.commit("Update")
} catch (error) {
  if (error.message.includes("nothing to commit")) {
    console.log("No changes to commit")
  } else if (error.message.includes("Author identity unknown")) {
    console.error("Git user not configured")
  } else {
    console.error("Unexpected error:", error.message)
  }
}

Next Steps

Creating Git Instance

Configure instances with debug mode

Working Directory

Handle directory-related errors

Build docs developers (and LLMs) love