{"record":{"id":"c758de0ecfcb2838","repo":"gitbutlerapp/gitbutler","slug":"no-push-remote-set-or-more-than-one-remote","errorCode":null,"errorMessage":"No push remote set or more than one remote","messagePattern":"No push remote set or more than one remote","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-action/src/lib.rs","lineNumber":149,"sourceCode":"                .project_meta()?\n                .target_ref_or_err()?\n                .to_string()\n                .parse()?;\n            gitbutler_branch_actions::set_base_branch(ctx, &target_ref, perm).map(|_| ())\n        }\n    }\n}\n\nfn default_target_setting_if_none(ctx: &Context) -> anyhow::Result<()> {\n    if ctx.project_meta()?.target_ref.is_some() {\n        return Ok(());\n    }\n    // Lets do the equivalent of `git symbolic-ref refs/remotes/origin/HEAD --short` to guess the default target.\n\n    let repo = ctx.repo.get()?;\n    let remote_name = repo\n        .remote_default_name(gix::remote::Direction::Push)\n        .ok_or_else(|| anyhow::anyhow!(\"No push remote set or more than one remote\"))?\n        .to_string();\n\n    let mut head_ref = repo\n        .find_reference(&format!(\"refs/remotes/{remote_name}/HEAD\"))\n        .map_err(|_| anyhow::anyhow!(\"No HEAD reference found for remote {remote_name}\"))?;\n    let target_ref_name = head_ref\n        .target()\n        .try_name()\n        .ok_or_else(|| anyhow::anyhow!(\"Remote HEAD for {remote_name} is not symbolic\"))?\n        .to_owned();\n\n    let head_commit = head_ref.peel_to_commit()?;\n\n    ctx.set_project_meta(ProjectMeta {\n        target_ref: Some(target_ref_name),\n        target_commit_id: Some(head_commit.id),\n        push_remote: None,\n    })?;","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-action/src/lib.rs#L131-L167","documentation":"When a project has no target branch configured (ctx.project_meta().target_ref is None), GitButler tries to guess one like `git symbolic-ref refs/remotes/origin/HEAD` using gix's remote_default_name(Push). That returns None when the repository has no push remote at all or several remotes with no unambiguous default (none named 'origin'), so default target setup in default_target_setting_if_none fails with this error.","triggerScenarios":"Any path through default_target_setting_if_none (e.g. prepare_handle_changes) on a repo with zero remotes, or multiple remotes none of which is 'origin' — gix cannot pick a default push remote, so the ok_or_else triggers.","commonSituations":"Fresh `git init` repo never given a remote; repos where origin was renamed (upstream + fork setups); exotic CI checkouts with many remotes; projects onboarded before a remote was added.","solutions":["Add or restore a remote named 'origin': git remote add origin <url> && git fetch origin (gix resolves 'origin' as the default).","If origin is absent, keep exactly one remote so remote_default_name is unambiguous.","Skip guessing entirely: set the target branch explicitly in GitButler project metadata / the app so target_ref.is_some() short-circuits this path.","For legitimate multi-remote setups, configure the workspace target once via the UI before running agent actions."],"exampleFix":"git remote add origin git@github.com:org/repo.git\ngit fetch origin\ngit remote set-head origin --auto\n# then retry the action, or set the target branch explicitly in the GitButler app","handlingStrategy":"validation","validationCode":"fn default_push_remote_is_unambiguous(repo: &gix::Repository) -> bool {\n    repo.remote_default_name(gix::remote::Direction::Push).is_some()\n}\n\n// run before any action that may guess the default target:\nif ctx.project_meta()?.target_ref.is_none()\n    && !default_push_remote_is_unambiguous(repo)\n{\n    anyhow::bail!(\"configure a target branch or add an 'origin' remote first\");\n}","typeGuard":null,"tryCatchPattern":"match default_target_setting_if_none(ctx) {\n    Err(err) if err.to_string().contains(\"No push remote\") => {\n        prompt_set_target_branch(); // writes ProjectMeta.target_ref so guessing is skipped\n    }\n    other => other?,\n}","preventionTips":["Keep a single canonical push remote, or name it 'origin'.","Persist target_ref in project metadata at onboarding so the guess path never runs.","Validate remote topology before enabling project actions."],"tags":["git-remote","target-branch","project-setup","gix"],"backgroundTag":"missing-git-remote","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}