gitbutlerapp/gitbutler · error
this is a placeholder for where we will have to start handli
Error message
this is a placeholder for where we will have to start handling this UnmergedTree
What it means
When but_workspace::commit builds ResolvedTips from stacks, stacks whose `workspacecommit_relation` is `MergeFrom` hit a `todo!`: these stacks must become parents of the workspace commit without being merged, and that UnmergedTree handling is not implemented yet. The comment notes callers may pass them as `Merged` on retry (crates/but-workspace/src/commit/mod.rs:254).
Source
Thrown at crates/but-workspace/src/commit/mod.rs:254
/// the workspace projection, used to preserve anonymous parents not represented in metadata.
///
/// `graph` resolves metadata branch names to commit and segment ids.
pub fn tips_from_metadata<'a>(
stacks: impl IntoIterator<Item = &'a but_core::ref_metadata::WorkspaceStack>,
anon_stacks: impl IntoIterator<Item = (usize, Tip)>,
graph: &but_graph::Graph,
) -> ResolvedTips {
let mut missing_stacks = Vec::new();
let mut tips_with_metadata_slots: Vec<_> = stacks
.into_iter()
.filter_map(|s| s.branches.first().map(|b| (b, s.workspacecommit_relation)))
.map(|(top_segment, relation)| {
match relation {
WorkspaceCommitRelation::Merged => {}
WorkspaceCommitRelation::MergeFrom { .. } => {
// These need to be part of the parents list, but shouldn't be merged.
// If the caller wants to retry them, they can be passed here as "Merged".
todo!(
"this is a placeholder for where we will have to start handling this UnmergedTree"
)
}
WorkspaceCommitRelation::Outside => return None,
}
let stack_tip_name = top_segment.ref_name.as_ref();
match graph.segment_and_commit_by_ref_name(stack_tip_name) {
None => {
missing_stacks.push(top_segment.ref_name.to_owned());
None
}
Some((segment, commit)) => Some(Tip {
name: Some(stack_tip_name.to_owned()),
commit_id: commit.id,
segment_idx: segment.id,
}),
}
})View on GitHub (pinned to caf1f223d3)
Solutions
- Retry with the offending stacks passed as `Merged` (the documented workaround in the source comment) if the calling API allows re-passing relations
- Restructure the workspace so no stack is in MergeFrom relation (unstack/absorb the merge) before committing
- Upgrade but-workspace once UnmergedTree handling is implemented; watch upstream for the todo removal
Defensive patterns
Strategy: validation
Validate before calling
// Filter or convert MergeFrom stacks before building tips
let retryable: Vec<_> = stacks.into_iter().map(|s| {
if s.workspacecommit_relation == WorkspaceCommitRelation::MergeFrom {
// documented workaround: pass as Merged on retry if the caller permits
s.with_relation(WorkspaceCommitRelation::Merged)
} else { s }
}).collect(); Type guard
fn has_mergefrom(stacks: &[Stack]) -> bool {
stacks.iter().any(|s| matches!(s.workspacecommit_relation, WorkspaceCommitRelation::MergeFrom))
} Prevention
- Check workspacecommit_relation of every stack before calling the tips/commit API
- Keep merge-parent-shaped stacks out of the workspace until UnmergedTree handling ships
- Wrap workspace commits in a pre-validation step that rejects MergeFrom with a clear upstream error
When it happens
Trigger: Committing the workspace when at least one stack relates to the workspace commit via `WorkspaceCommitRelation::MergeFrom` - e.g. merge-shaped workspace topologies or imported stacks that arrive as merge parents.
Common situations: Repos with merge commits inside the workspace topology; import/sync flows that produce MergeFrom relations; newer workspace-import features exercising this relation for the first time.
Related errors
- swap connections of nodes as well
- implement list and call recursively
- broker already configured
- broker has not been configured
- BUG: {id} is queued
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/020a1677ef4d1989.
Report an issue: GitHub.