gitbutlerapp/gitbutler · error
swap connections of nodes as well
Error message
swap connections of nodes as well
What it means
`swap_commits_and_connections` in but-graph's init/walk swaps the commit vectors of two segments, but only when neither segment has graph edges. If either segment has connections (PetGraph edges), it panics with `todo!` - rewiring the connections during the swap was never implemented (crates/but-graph/src/init/walk/mod.rs:352).
Source
Thrown at crates/but-graph/src/init/walk/mod.rs:352
pub fn swap_queued_segments(queue: &mut Queue, a: SegmentIndex, b: SegmentIndex) {
for instruction_to_replace in queue.iter_mut().map(|(_, _, instruction, _)| instruction) {
let cmp = instruction_to_replace.segment_idx();
if cmp == a {
*instruction_to_replace = instruction_to_replace.with_replaced_sidx(b);
} else if cmp == b {
*instruction_to_replace = instruction_to_replace.with_replaced_sidx(a);
}
}
}
pub fn swap_commits_and_connections(graph: &mut PetGraph, a: SegmentIndex, b: SegmentIndex) {
{
let (a, b) = graph.index_twice_mut(a, b);
std::mem::swap(&mut a.commits, &mut b.commits);
}
if graph.edges(a).next().is_some() || graph.edges(b).next().is_some() {
todo!("swap connections of nodes as well")
}
}
fn local_branches_by_id(
refs_by_id: &RefsById,
id: gix::ObjectId,
) -> Option<impl Iterator<Item = &gix::refs::FullName> + '_> {
refs_by_id.get(&id).map(|refs| {
refs.iter()
.filter(|rn| rn.category() == Some(Category::LocalBranch))
})
}
/// Split `src_sidx` into a new segment (to receive the commit at `info`) and connect it with the new segment
/// whose id will be returned, if…
///
/// * …there is exactly one eligible branch to name it.
/// * …it is a merge commit.View on GitHub (pinned to caf1f223d3)
Solutions
- Avoid code paths that reorder connected segments - restructure the walk so only edge-free segments are swapped
- Upgrade but-graph; track the upstream implementation of edge rewiring
- As a maintainer: implement the edge swap by collecting `EdgeReference`s for both indices and re-adding them with swapped endpoints via `graph.add_edge` before removing the old ones
Defensive patterns
Strategy: validation
Validate before calling
// Only swap edge-free segments
fn can_swap(graph: &PetGraph, a: SegmentIndex, b: SegmentIndex) -> bool {
graph.edges(a).next().is_none() && graph.edges(b).next().is_none()
}
if can_swap(&graph, a, b) {
swap_commits_and_connections(&mut graph, a, b);
} else {
// pick a different rewrite strategy for connected segments
} Prevention
- Before swapping segments, assert both have degree zero with graph.edges(...).next().is_none()
- Keep reordering passes on standalone segments; route connected reorders through implemented graph edits
- Pin but-graph versions in lockstep with the walk passes you depend on
When it happens
Trigger: A graph-rewriting pass (ordering/topology fixups during init) calls this with two segments where `graph.edges(a)` or `graph.edges(b)` yields at least one edge - i.e. either segment is connected to the rest of the graph rather than standing alone.
Common situations: Repositories whose ref graph produces connected segments that the walk wants to reorder; new graph-manipulation code paths added to init; changes to segment sorting rules.
Related errors
- this is a placeholder for where we will have to start handli
- BUG: {id} is queued
- prefiltered
- implement list and call recursively
- broker already configured
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/884a552bf59832a5.
Report an issue: GitHub.