zed-industries/zed · error

git diff-tree failed: {stderr}

Error message

git diff-tree failed: {stderr}

What it means

While computing a tree diff for a comparison, the code runs `git diff-tree` between a base ref and HEAD; a non-zero exit surfaces git's stderr here. As with all such wrappers, the real cause is in the appended stderr text.

Source

Thrown at crates/git/src/repository.rs:1909

            .boxed()
    }

    fn status(&self, path_prefixes: &[RepoPath]) -> Task<Result<GitStatus>> {
        let git = self.git_binary_in_worktree();
        let args = git_status_args(path_prefixes);
        log::debug!("Checking for git status in {path_prefixes:?}");
        self.executor.spawn(async move {
            let git = git?;
            let output = git.build_command(&args).output().await?;
            if output.status.success() {
                let stdout = String::from_utf8_lossy(&output.stdout);
                stdout.parse()
            } else {
                let stderr = String::from_utf8_lossy(&output.stderr);
                anyhow::bail!("git status failed: {stderr}");
            }
        })
    }

    fn check_access(&self) -> BoxFuture<'_, Result<()>> {
        let git = self.git_binary_in_worktree();
        self.executor
            .spawn(async move {
                git?.run(&["rev-parse"]).await?;
                Ok(())
            })
            .boxed()
    }

    fn diff_tree(&self, request: DiffTreeType) -> BoxFuture<'_, Result<TreeDiff>> {
        let git = self.git_binary_in_worktree();
        let working_directory = self.working_directory.clone();
        let merge_base_ref = match &request {
            DiffTreeType::MergeBaseWithWorktree { base } => Some(base.clone()),
            DiffTreeType::MergeBase { .. } | DiffTreeType::Since { .. } => None,
        };

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Check the appended stderr for the failing revision name.
  2. Treat unborn HEAD as an empty diff and skip the diff-tree call until the first commit exists.
  3. Validate the base ref resolves: `git rev-parse --verify <base_ref>`.
  4. If stderr says `bad object`, run `git fsck`; re-clone if the object store is damaged.
Defensive patterns

Strategy: try-catch

Validate before calling

// skip diffs while HEAD is unborn (repo with no commits)
if git.run(&["rev-parse", "--verify", "--quiet", "HEAD"]).await.is_err() {
    return Ok(TreeDiff::default());
}

Try / catch

match repo.diff_for_paths(..).await {
    Err(e) if e.to_string().contains("diff-tree failed") && e.to_string().contains("bad revision HEAD") => {
        Ok(TreeDiff::default()) // unborn branch: no diff yet
    }
    other => other?,
}

Prevention

When it happens

Trigger: `git diff-tree ... HEAD` fails when HEAD is unborn (a fresh repo or new branch with zero commits yields `fatal: bad revision HEAD`), when the base/merge-base ref does not resolve, when the object database is corrupt (`fatal: bad object`), or on repository permission problems.

Common situations: Opening comparisons on a brand-new repository with no initial commit; comparing against a ref that was deleted or pruned; interrupted clones leaving a broken object store; worktrees created from an empty branch.

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 zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/1307dabd7050eb10. Report an issue: GitHub.