gitbutlerapp/gitbutler · warning

No uncommitted changes assigned to branch: {branch_name}

Error message

No uncommitted changes assigned to branch: {branch_name}

What it means

The absorb plan found the stack owning the requested branch, but none of the current hunk assignments carry that stack's ID — no uncommitted changes are assigned to the branch — so there is nothing to absorb and the plan bails. It is effectively a nothing-to-do condition reported as an error.

Source

Thrown at crates/but-api/src/legacy/absorb.rs:164

                .iter()
                .find(|s| {
                    s.heads
                        .iter()
                        .any(|h| h.name.to_str().map(|n| n == branch_name).unwrap_or(false))
                })
                .ok_or_else(|| anyhow::anyhow!("Branch not found: {branch_name}"))?;

            let stack_id = stack.id.ok_or_else(|| anyhow::anyhow!("Stack has no ID"))?;

            // Filter assignments to just this stack
            let candidates: Vec<AbsorbCandidate> = all_assignments
                .into_iter()
                .filter(|a| a.stack_id == Some(stack_id))
                .map(Into::into)
                .collect();

            if candidates.is_empty() {
                anyhow::bail!("No uncommitted changes assigned to branch: {branch_name}");
            }

            (candidates, dependencies)
        }
        AbsorptionTarget::TreeChanges {
            changes,
            assigned_stack_id,
        } => {
            // Get all worktree changes, assignments, and dependencies
            let worktree_changes = crate::diff::changes_in_worktree_with_perm(
                ctx,
                ChangesSource::Head,
                true,
                perm.read_permission(),
            )?;
            let all_assignments = worktree_changes.assignments;
            let dependencies = worktree_changes.dependencies;

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Assign the pending changes to the branch (hunk assignment UI or equivalent) and retry.
  2. Or use the TreeChanges absorption target to absorb explicitly selected files.
  3. Confirm with `but status` that the branch actually has assigned uncommitted changes before planning.

Example fix

let plan = match absorption_plan_with_perm(ctx, AbsorptionTarget::Branch { branch_name: name.clone() }, perm) {
    Err(e) if e.to_string().contains("No uncommitted changes assigned") => vec![], // nothing to do
    other => other?,
};
Defensive patterns

Strategy: validation

Validate before calling

let changes = diff::changes_in_worktree_with_perm(
    ctx,
    ChangesSource::Head,
    true,
    perm.read_permission(),
)?;
let assigned: Vec<_> = changes
    .assignments
    .iter()
    .filter(|a| a.stack_id == Some(stack_id))
    .collect();
if assigned.is_empty() {
    // skip absorb for this branch instead of calling the planner
}

Try / catch

let plan = match absorption_plan_with_perm(ctx, AbsorptionTarget::Branch { branch_name }, perm) {
    Err(e) if e.to_string().contains("No uncommitted changes assigned") => vec![], // nothing to do
    other => other?,
};

Prevention

When it happens

Trigger: absorption_plan_with_perm(Branch) where worktree changes are all unassigned or assigned to other stacks, or the worktree is clean for that branch: candidates filtered by a.stack_id == Some(stack_id) come back empty.

Common situations: User forgot to drag/assign changes onto the branch in the UI; absorbing right after committing everything; assignments lost after a crash or workspace reset.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/97bef06ed45c80d2. Report an issue: GitHub.