denoland/deno · error · anyhow::Error

`git ` failed

Error message

`git {}` failed: {}

What it means

run_git got git to start but it exited non-zero; the message embeds the exact git arguments and git's own stderr (cli/util/git.rs:25-31). Callers add context — `deno test --changed` wraps the rev-parse failure as "`--changed` requires a git repository" — so the underlying causes are repository state problems: not a repo, unborn branch with no commits, an unknown base ref for --changed=..., or detached/partial checkouts in release tooling.

Solutions

  1. Read the embedded stderr — it is git's own diagnostic and names the real problem.
  2. For --changed outside a repo: git init && commit, or run plain `deno test` instead.
  3. For --changed=<base>: confirm the ref exists (`git branch --list`, `git rev-parse <base>`) and update it (e.g. main vs master).
  4. For a locked/corrupt index: ensure no other git process is running, then `git status` to surface index damage.

Example fix

# before
$ deno test --changed=master
error: `git diff --name-only master...HEAD` failed: fatal: ambiguous argument 'master...HEAD': unknown revision

# after — use a ref that exists in this clone
git branch --list   # shows 'main'
deno test --changed=main
Defensive patterns

Strategy: validation

Validate before calling

# Validate repo state before asking deno to diff it
git rev-parse --is-inside-work-tree >/dev/null || { echo 'not a git repo'; exit 1; }
git rev-parse --verify "$BASE" >/dev/null 2>&1 || { echo "unknown base ref: $BASE"; exit 1; }
deno test --changed="$BASE"

Try / catch

# Capture deno's exit and surface the embedded git stderr when it fails
if ! out=$(deno test --changed 2>&1); then
  echo "$out" | grep -A3 'git .* failed' || true
  exit 1
fi

Prevention

When it happens

Trigger: deno test --changed outside a git repo (`git rev-parse --show-toplevel` exits 128); --changed=<base> naming a ref that does not exist; a repo whose HEAD is unborn (no initial commit); git diff/ls-files failing on a corrupt index.

Common situations: Running --changed before the first commit; base branch renamed (master→main) leaving stale CI config; shallow clones missing the merge-base; git index locked by a concurrent process.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/f3fe818e87a214da. Report an issue: GitHub.

Appendix: source

Thrown at cli/util/git.rs:26

use tokio::process::Command;

/// Run `git` with `args` in `cwd`, returning stdout on success.
pub fn run_git(cwd: &Path, args: &[&str]) -> Result<String, AnyError> {
  let output = match std::process::Command::new("git")
    .current_dir(cwd)
    .args(args)
    .output()
  {
    Ok(output) => output,
    Err(err) => {
      return Err(anyhow!(
        "Failed to run `git {}`: {err}. Is git installed and on PATH?",
        args.join(" ")
      ));
    }
  };
  if !output.status.success() {
    return Err(anyhow!(
      "`git {}` failed: {}",
      args.join(" "),
      String::from_utf8_lossy(&output.stderr).trim()
    ));
  }
  Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}

pub async fn check_if_git_repo_dirty(cwd: &Path) -> Option<String> {
  let bin_name = if cfg!(windows) { "git.exe" } else { "git" };

  //  Check if git exists
  let git_exists = Command::new(bin_name)
    .arg("--version")
    .stderr(Stdio::null())
    .stdout(Stdio::null())
    .status()
    .await

View on GitHub (pinned to 9ad36f7a2c)