gitbutlerapp/gitbutler · error

Failed to determine push remote for dry-run push: workspace

Error message

Failed to determine push remote for dry-run push: workspace target has no push remote.

What it means

`but push --dry-run` resolves the workspace target under a shared lock and needs its push remote to describe what a real push would update. `ResolvedTarget::resolve_with_perm(...)?.push_remote_name()` returning `None` aborts the dry run with this error before any branch analysis happens.

Source

Thrown at crates/but/src/command/legacy/push.rs:228

                t.hint.paint("No branches have unpushed commits.")
            )?;
        }
        return Ok(());
    }

    // Get detailed information for each branch
    let mut dry_run_infos = Vec::new();

    let stacks = crate::legacy::workspace::applied_stacks_with_expensive_commit_info(ctx)?;

    // Limit the shared lock to target resolution before continuing with dry-run analysis.
    let fallback_remote = {
        let guard = ctx.shared_worktree_access();
        workspace_target::ResolvedTarget::resolve_with_perm(ctx, guard.read_permission())?
            .push_remote_name()
            .map(str::to_owned)
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Failed to determine push remote for dry-run push: workspace target has no push remote."
                )
            })?
    };
    let repo = ctx.repo.get()?.clone().for_commit_shortening();
    let remote_names = repo.remote_names();
    for (branch_name, unpushed_count, stack_name) in &branches_to_show {
        // Find the stack containing this branch
        for stack_entry in &stacks {
            if stack_entry.id.is_some()
                && let Some(branch_detail) = stack_entry.branch(branch_name)
            {
                let remote_ref = match repo
                    .branch_remote_tracking_ref_name(
                        branch_detail.reference.as_ref(),
                        gix::remote::Direction::Fetch,
                    )
                    .transpose()?

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Set target together with a push remote: `but config target <branch> <push-remote>` (e.g. `but config target origin/main origin`)
  2. Or set the push remote alone: `but config push-remote <remote>`
  3. Check `git remote -v` and run `git fetch` so the target ref exists on that remote
  4. Re-run `but push --dry-run`

Example fix

# before
but push --dry-run
# error: Failed to determine push remote for dry-run push: workspace target has no push remote.

# after
but config push-remote origin
but push --dry-run
Defensive patterns

Strategy: validation

Validate before calling

# Ensure target + push remote before any dry-run in scripts
but config target origin/main origin
git remote -v | grep -q '^origin' || { echo 'missing remote: origin' >&2; exit 1; }
but push --dry-run

Prevention

When it happens

Trigger: Running `but push --dry-run` when the workspace target carries no push remote: target branch never fully configured, push remote not derivable from the target ref, or the remote missing from the repo.

Common situations: Target set without an explicit push remote on an unusual remote layout; remote renamed (origin to upstream) after onboarding; fresh clone with partially applied workspace config.

Related errors


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