gitbutlerapp/gitbutler · error
No HEAD reference found for remote
Error message
No HEAD reference found for remote {remote_name} What it means
After determining the default push remote, default_target_setting_if_none looks up refs/remotes/<remote>/HEAD, which encodes the remote's default branch. If that symbolic reference does not exist in the local repo, this error is thrown, because without it GitButler cannot guess which branch should be the workspace target.
Solutions
- Recreate the remote HEAD: `git remote set-head origin --auto` (queries the remote for its default branch), then retry.
- Or set it manually: `git remote set-head origin main` (or the actual default branch).
- Run a full fetch (`git fetch origin`) to populate remote-tracking refs if the clone is single-branch.
- Configure the GitButler target branch explicitly to skip the guesswork.
Example fix
// before $ git branch -r origin/main # but no origin/HEAD // after $ git remote set-head origin --auto $ retry operation
Defensive patterns
Strategy: validation
Validate before calling
if repo.find_reference("refs/remotes/origin/HEAD").is_err() {
// repair before calling the API:
// git remote set-head origin --auto
} Try / catch
match default_target_setting_if_none(ctx) {
Err(e) if e.to_string().contains("No HEAD reference found") => {
// run `git remote set-head <remote> --auto`, then retry
}
other => other?,
} Prevention
- Run `git remote set-head <remote> --auto` after cloning, especially for single-branch or shallow clones.
- Avoid single-branch fetch configs that skip refs/remotes/<remote>/HEAD.
- Set the GitButler target explicitly in projects whose remote HEAD is unreliable.
When it happens
Trigger: default_target_setting_if_none calls repo.find_reference("refs/remotes/{remote_name}/HEAD") and the ref is absent — the clone was made with a git version/setting that skips remote HEAD, or no fetch has populated remote-tracking refs yet.
Common situations: Shallow or partial clones missing remote-tracking refs; repos cloned with remote.origin.fetch configured narrowly (single-branch clone) so refs/remotes/origin/HEAD was never created; a bare/mirrored setup copied without the HEAD symref.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Remote HEAD for is not symbolic
- Attempted to update the symbolic reference
- Can't handle reference
- Cannot currently handle remotes as start position
- DefaultTargetNotFound
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/bd4711c54fdeb8df.
Report an issue: GitHub.
Appendix: 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 58e5313667)