gitbutlerapp/gitbutler · error

Repository has no working directory

Error message

Repository has no working directory

What it means

Thrown by `setup_local_remote` when `repo.workdir()` returns `None`. Creating the `gb-local` remote requires a filesystem path for the working directory; a bare or workdir-less repository has none, so setup aborts.

Solutions

  1. Ensure the repo is non-bare: `git config core.bare false` if applicable.
  2. Run setup from the main, checked-out clone of the repository.
  3. Re-clone the repository to restore a valid working directory.

Example fix

// before
cd ~/myrepo.git && but setup
// after
git clone ~/myrepo.git ~/myrepo
cd ~/myrepo && but setup
Defensive patterns

Strategy: validation

Validate before calling

const toplevel = await run(['git', '-C', repoPath, 'rev-parse', '--show-toplevel']);
if (!toplevel.trim()) {
  throw new Error(`${repoPath} has no working directory; use a non-bare clone`);
}

Type guard

function hasWorkdir(p: string): boolean {
  const r = cp.spawnSync('git', ['-C', p, 'rev-parse', '--show-toplevel']);
  return r.status === 0 && r.stdout.toString().trim().length > 0;
}

Try / catch

try {
  await run(['but', 'setup', repoPath]);
} catch (e) {
  if (String(e).includes('no working directory')) {
    console.error('Setup requires a non-bare clone with a checked-out worktree.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `but setup` on a repository where gix reports no working directory (bare repo, `core.bare=true`, or repo opened without a worktree) during local-remote setup.

Common situations: Setup invoked against a bare clone; `.git/config` with `bare = true` in a checked-out repo; unusual worktree setups where gix cannot resolve the workdir.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/8e3f82b058dcce8a. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/command/legacy/setup.rs:588

    if ws.push_remote_name().is_none()
        && repo
            .remote_default_name(gix::remote::Direction::Push)
            .is_none()
    {
        anyhow::bail!(
            "Neither found push remote found in workspace nor unambiguously in the Git repository configuration."
        )
    };

    Ok(true)
}

/// Creates a 'gb-local' remote pointing to this repository and creates tracking refs for the default branch.
fn setup_local_remote(repo: &gix::Repository, out: &mut OutputChannel) -> anyhow::Result<String> {
    let t = theme::get();
    let repo_url = repo
        .workdir()
        .ok_or_else(|| anyhow::anyhow!("Repository has no working directory"))?
        .to_str()
        .ok_or_else(|| anyhow::anyhow!("Repository path is not valid UTF-8"))?;

    if let Some(out) = out.for_human() {
        writeln!(
            out,
            "  {}",
            t.info
                .paint("No push remote found, creating gb-local remote...")
        )?;
    }

    edit_repo_config(repo, gix::config::Source::Local, |config| {
        let mut section = config.section_mut_or_create_new("remote", Some("gb-local".into()))?;
        section.push("url", repo_url)?;
        Ok(())
    })?;

View on GitHub (pinned to 58e5313667)