gitbutlerapp/gitbutler · error
No HEAD reference found for remote {remote_name}
Error message
No HEAD reference found for remote {remote_name} What it means
While guessing the default target branch, GitButler looks up refs/remotes/<remote>/HEAD (the symref `git remote set-head` creates). If that reference does not exist, find_reference fails and default_target_setting_if_none aborts with this message naming the remote. The remote itself is configured; only its HEAD shortcut is missing.
Source
Thrown at crates/but-action/src/lib.rs:154
}
}
}
fn default_target_setting_if_none(ctx: &Context) -> anyhow::Result<()> {
if ctx.project_meta()?.target_ref.is_some() {
return Ok(());
}
// Lets do the equivalent of `git symbolic-ref refs/remotes/origin/HEAD --short` to guess the default target.
let repo = ctx.repo.get()?;
let remote_name = repo
.remote_default_name(gix::remote::Direction::Push)
.ok_or_else(|| anyhow::anyhow!("No push remote set or more than one remote"))?
.to_string();
let mut head_ref = repo
.find_reference(&format!("refs/remotes/{remote_name}/HEAD"))
.map_err(|_| anyhow::anyhow!("No HEAD reference found for remote {remote_name}"))?;
let target_ref_name = head_ref
.target()
.try_name()
.ok_or_else(|| anyhow::anyhow!("Remote HEAD for {remote_name} is not symbolic"))?
.to_owned();
let head_commit = head_ref.peel_to_commit()?;
ctx.set_project_meta(ProjectMeta {
target_ref: Some(target_ref_name),
target_commit_id: Some(head_commit.id),
push_remote: None,
})?;
Ok(())
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, EnumString, Default)]
#[serde(rename_all = "camelCase")]View on GitHub (pinned to 2497b8007a)
Solutions
- Run git remote set-head <remote> --auto to (re)create refs/remotes/<remote>/HEAD.
- If --auto cannot query the remote, set it explicitly: git remote set-head <remote> main.
- Or set the target branch directly in GitButler so the guess path never runs.
- Verify with git symbolic-ref refs/remotes/<remote>/HEAD.
Example fix
git remote set-head origin --auto git symbolic-ref refs/remotes/origin/HEAD # should print refs/remotes/origin/<branch> # then retry the GitButler action
Defensive patterns
Strategy: validation
Validate before calling
fn remote_head_exists(repo: &gix::Repository, remote: &str) -> bool {
repo.find_reference(&format!("refs/remotes/{remote}/HEAD")).is_ok()
}
// before the first GitButler action on a repo:
if !remote_head_exists(repo, &remote_name) {
std::process::Command::new("git")
.args(["remote", "set-head", &remote_name, "--auto"])
.status()?;
} Try / catch
match default_target_setting_if_none(ctx) {
Err(err) if err.to_string().contains("No HEAD reference found for remote") => {
run_git(&["remote", "set-head", &remote, "--auto"]); // then retry once
}
r => r?,
} Prevention
- Run git remote set-head <remote> --auto right after adding any remote.
- Avoid --single-branch clones for projects managed by GitButler.
- Persist an explicit target_ref at project setup instead of relying on discovery.
When it happens
Trigger: default_target_setting_if_none on a repo whose push remote has no refs/remotes/<remote>/HEAD: remotes added with `git remote add` but never given a HEAD, shallow or --single-branch clones, repos materialized by scripts that skip the symref.
Common situations: git clone --single-branch / --depth clones; tooling and containers that construct remotes manually; older Git clients that did not write remote HEAD; mirror setups.
Related errors
- Remote HEAD for {remote_name} is not symbolic
- No push remote set or more than one remote
- Target branch {target_ref_name} not found
- Branch {branch_name} not found
- No base branch configured
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/bd4711c54fdeb8df.
Report an issue: GitHub.