GitoxideLabs/gitoxide · error

a tree change cannot be amended from the worktree

Error message

a tree change cannot be amended from the worktree

What it means

During an amend, `amend_path_tree` can apply a single path change taken from the index or the worktree, but a `ChangeGroup::Tree` change is a whole-tree (submodule/tree-entry) change that cannot be reproduced by rebuilding trees from worktree state. The library intentionally refuses rather than silently producing a wrong tree. Callers must re-run the operation without amending, or handle tree changes separately.

Solutions

  1. Amend only file (blob) changes; leave tree changes such as submodule pointer updates to a new commit or to `git submodule update`.
  2. Update the submodule to a recorded state so the change stops appearing as a tree change, then retry the amend.
  3. If support for amending tree changes is desired, implement it via tree editors (apply_path_from_tree) instead of the worktree path.

Example fix

// before: selecting a submodule change and amending
tix amend  # ChangeGroup::Tree -> bail

// after: stage only file changes, or commit the submodule bump separately
let changes: Vec<_> = changes.into_iter().filter(|c| c.group != ChangeGroup::Tree).collect();
Defensive patterns

Strategy: validation

Validate before calling

// Rust: check the change group before amending
if change.group == crate::ChangeGroup::Tree {
    eprintln!("skip amend: tree change {:?}", change.path);
} else {
    amend(repo, change)?;
}

Type guard

fn is_amendable(change: &PathChange) -> bool {
    matches!(change.group, crate::ChangeGroup::Staged | crate::ChangeGroup::Unstaged)
}

Prevention

When it happens

Trigger: Calling the tix amend path so that `perform_inner` dispatches `amend_path_tree` with a `PathChange` whose `group` is `crate::ChangeGroup::Tree` — i.e. the selected change is a tree (e.g. submodule pointer) change rather than a staged or unstaged file change.

Common situations: Amending a commit that changed a submodule pointer or other gitlink/tree entry; selecting a tree-type entry in the interactive change list and asking tix to fold it into the head commit.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/dd632354ffc35575. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/head.rs:217

    index: &gix::index::File,
) -> Result<ObjectId> {
    match change.group {
        crate::ChangeGroup::Staged => {
            let index_tree = create::index_tree(repo, index)?;
            apply_path_from_tree(repo, commit_tree, index_tree, change)
        }
        crate::ChangeGroup::Unstaged => {
            let baseline = repo.find_tree(commit_tree)?;
            create::worktree_tree_with_changes(
                repo,
                &baseline,
                &crate::Changes {
                    paths: vec![change.clone()],
                    ..crate::Changes::default()
                },
            )
        }
        crate::ChangeGroup::Tree => anyhow::bail!("a tree change cannot be amended from the worktree"),
    }
}

fn apply_path_from_tree(
    repo: &gix::Repository,
    commit_tree: ObjectId,
    source_tree: ObjectId,
    change: &PathChange,
) -> Result<ObjectId> {
    let mut editor = repo.find_tree(commit_tree)?.edit()?;
    if change.kind == ChangeKind::Renamed
        && let Some(source) = &change.source
    {
        editor.remove(source)?;
    }
    if change.kind == ChangeKind::Deleted {
        editor.remove(&change.path)?;
    } else {

View on GitHub (pinned to e73179060b)