gitbutlerapp/gitbutler · error · anyhow::Error

Cannot currently handle remotes as start position

Error message

Cannot currently handle remotes as start position

What it means

Thrown by but-graph's init (crates/but-graph/src/init/mod.rs:954) when the requested start position ref_name is a remote-tracking branch (Category::RemoteBranch, e.g., refs/remotes/origin/main). The code carries an explicit TODO: Git itself refuses to check out remote-tracking branches by name, and the initial traversal flags would need special setup (plus a guard against traversing the ref twice, once as tip and once by discovery). So today this input is rejected up front rather than mis-behaving later.

Source

Thrown at crates/but-graph/src/init/mod.rs:954

        };
        let Options {
            collect_tags,
            extra_target_commit_id,
            commits_limit_hint: limit,
            commits_limit_recharge_location: mut max_commits_recharge_location,
            hard_limit,
            dangerously_skip_postprocessing_for_debugging,
            worktrees: _,
        } = options;
        let max_limit = Limit::new(limit);
        if ref_name
            .as_ref()
            .is_some_and(|name| name.category() == Some(Category::RemoteBranch))
        {
            // TODO: see if this is a thing - Git doesn't like to checkout remote tracking branches by name,
            //       and if we should handle it, we need to setup the initial flags accordingly.
            //       Also we have to assure not to double-traverse the ref, once as tip and once by discovery.
            bail!("Cannot currently handle remotes as start position");
        }
        let commit_graph = repo.commit_graph_if_enabled()?;
        let shallow_commits = repo.shallow_commits()?;
        let mut buf = Vec::new();

        let configured_remote_tracking_branches =
            remotes::configured_remote_tracking_branches(repo)?;
        let initial_tips = initial_tips_from_tips(
            repo,
            tips,
            &graph.project_meta,
            extra_target_commit_id,
            worktree_tips,
        )?;
        graph.traversal_tips = initial_tips.tips.clone();
        let refs_by_id = repo.collect_ref_mapping_by_prefix(
            [
                "refs/heads/",

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Pass the local branch name instead (refs/heads/main); create it first if missing: `git branch main origin/main`
  2. Or peel the remote ref to a commit id and use that commit as the start position instead of a ref name
  3. If you actually want a detached start, resolve the remote ref to its OID and pass the commit

Example fix

// before
let graph = but_graph::init(repo, InitOptions { ref_name: Some("origin/main".into()), .. })?; // bails: RemoteBranch

// after
let oid = repo.find_reference("refs/remotes/origin/main")?.peel_to_commit()?.id();
let graph = but_graph::init(
    repo,
    InitOptions {
        ref_name: Some("refs/heads/main".into()), // local branch
        extra_target_commit_id: Some(oid),        // remote tip as extra target
        ..Default::default()
    },
)?;
Defensive patterns

Strategy: validation

Validate before calling

// Reject or rewrite remote-tracking start positions before init
use but_graph::Category;
let ref_name = match ref_name {
    Some(name) if name.category() == Some(Category::RemoteBranch) => {
        // peel to the commit and use it instead of the remote ref
        let oid = repo.find_reference(name.as_ref())?.peel_to_commit_in_place()?;
        Some(repo.find_reference(main_branch_name)?.name().to_owned()) // local branch
            .map(|n| (n, Some(oid)))
            .map(|(n, o)| { extra_target_commit_id = o; n })
            .unwrap()
    }
    other => other,
};

Type guard

fn is_remote_tracking(name: &gix::refs::FullName) -> bool {
    name.category() == Some(but_graph::Category::RemoteBranch)
}

Try / catch

match but_graph::init(repo, opts) {
    Ok(g) => g,
    Err(err) if err.to_string().contains("remotes as start position") => {
        bail!("remote-tracking branches cannot start a graph; pass the local branch or a commit id")
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Building a graph with ref_name = Some("refs/remotes/origin/main") or the shorthand "origin/main"; tooling that resolves 'default branch' to the remote-tracking ref instead of a local branch; attempts to start a workspace directly from a fetched remote state.

Common situations: Fresh clones where the local branch has not been created yet and only origin/main exists; scripts feeding `git rev-parse --symbolic-full-name` output straight into but-graph; users expecting remote refs to behave like local branches.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/77ef871129815463. Report an issue: GitHub.