gitbutlerapp/gitbutler · error

BUG: Cannot possibly not have any changes here

Error message

BUG: Cannot possibly not have any changes here

What it means

Panic while resolving committed-changes sources for move: after pushing each selected committed file via push_changes_from_committed_file, the accumulated DiffSpec list is empty. Selection guarantees at least one committed file, so an empty result means the builder matched nothing - a selected path that is absent from the referenced commit (rename, case or unicode-normalization mismatch) silently appended no changes.

Source

Thrown at crates/but/src/command/legacy/move.rs:840

        (None, Some(files), None) => {
            let mut builder = DiffSpecBuilder::new(repo, context_lines);
            let source_commit = files.head.0.clone();
            for (commit, path) in files {
                if commit.as_ref() != source_commit.as_ref() {
                    return Err(
                        bad_input("Cannot move changes from multiple commits")
                            .hint("Move changes from a single commit at first, then squash additional changes into the new commit")
                            .into()
                    );
                }

                builder.push_changes_from_committed_file(commit.commit_id, path.as_bstr())?;
            }

            // It doesn't appear as if we need to sort DiffSpecs when they're resolved on a file
            // level. For the future hunk level DiffSpecs we may need to, however.
            let changes = NonEmpty::from_vec(builder.into_diff_specs())
                .expect("BUG: Cannot possibly not have any changes here");

            Ok(ResolvedSources::CommittedChanges((source_commit, changes)))
        }
        (None, None, Some(branches)) => {
            if !branches.tail.is_empty() {
                Err(bad_input("Branches can only be moved one at a time")
                    .arg_name("<SOURCES>")
                    .into())
            } else {
                Ok(ResolvedSources::Branch(branches.head))
            }
        }
        (None, None, None) => panic!("BUG: It should not be possible to omit sources"),
        (_, _, _) => Err(bad_input("Mixing source types is not allowed")
            .hint("You can only move one kind of source (e.g. commits) at a time")
            .arg_name("<SOURCES>")
            .into()),
    }

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Re-derive the selection from the current commit state (diff view or 'but commit list') and retry
  2. Check exact path casing and unicode normalization against 'git ls-tree <commit>'
  3. Maintainer: make push_changes_from_committed_file report when a path matches nothing so the failure is explained instead of panicking later

Example fix

// before
builder.push_changes_from_committed_file(commit.commit_id, path.as_bstr())?;
// ...
let changes = NonEmpty::from_vec(builder.into_diff_specs())
    .expect("BUG: Cannot possibly not have any changes here");

// after - fail per path so an empty result is explained where it happens
let specs = builder.push_changes_from_committed_file(commit.commit_id, path.as_bstr())?;
if specs == 0 {
    anyhow::bail!("path {} not found in commit {}", path.as_bstr(), commit.commit_id);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before building the move operation, confirm each selected path exists in the commit
let tree = repo.find_tree(commit_id)?;
for path in paths.iter() {
    if tree.lookup_entry_by_path(path.as_bstr() as &bstr::BStr).is_err() {
        anyhow::bail!("path {} not present in commit {}", path.as_bstr(), commit_id);
    }
}

Prevention

When it happens

Trigger: Selecting a committed file whose path no longer exists in that commit (renamed between commits); case-sensitivity differences on case-insensitive filesystems; NFC/NFD unicode normalization differences (typical on macOS); a file selection computed against a different commit than the one passed in.

Common situations: Moving changes right after a rename; paths copied from older tooling output with different normalization; cross-platform checkouts normalizing filenames.

Related errors


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