Skip to content

Commit ee8217d

Browse files
committed
Assure that the lower base of the workspace is always owned by another segment.
1 parent a9c736b commit ee8217d

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

crates/but-graph/src/init/post.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl Graph {
7777
// We perform view-related updates here for convenience, but also because the graph
7878
// traversal should have nothing to do with workspace details. It's just about laying
7979
// the foundation for figuring out our workspaces more easily.
80-
self.workspace_upgrades(meta, repo)?;
80+
self.workspace_upgrades(meta, repo, &refs_by_id)?;
8181

8282
// Point entrypoint to the right spot after all the virtual branches were added.
8383
self.set_entrypoint_to_ref_name(meta)?;
@@ -352,6 +352,23 @@ impl Graph {
352352
);
353353
self.inner.remove_edge(edge.id);
354354
}
355+
356+
if cidx_for_new_segment == 0 {
357+
// The top-segment is still connected with edges that think they link to a commit, so adjust them.
358+
let edges_to_adjust: Vec<_> = self
359+
.inner
360+
.edges_directed(sidx, Direction::Incoming)
361+
.map(|e| e.id())
362+
.collect();
363+
for edge_id in edges_to_adjust {
364+
let edge = self
365+
.inner
366+
.edge_weight_mut(edge_id)
367+
.expect("still present as we just saw it");
368+
edge.dst = None;
369+
edge.dst_id = None;
370+
}
371+
}
355372
Ok(new_segment_sidx)
356373
}
357374

@@ -532,13 +549,22 @@ impl Graph {
532549
&mut self,
533550
meta: &OverlayMetadata<'_, T>,
534551
repo: &OverlayRepo<'_>,
552+
refs_by_id: &RefsById,
535553
) -> anyhow::Result<()> {
536-
let Some((ws_sidx, ws_stacks, ws_data, ws_target)) = self
554+
let Some((ws_sidx, ws_stacks, ws_data, ws_target, ws_low_bound_sidx)) = self
537555
.to_workspace_inner(workspace::Downgrade::Disallow)
538556
.ok()
539557
.and_then(|mut ws| {
540558
let md = ws.metadata.take();
541-
md.map(|md| (ws.id, ws.stacks, md, ws.target))
559+
md.map(|md| {
560+
let lower_bound_if_in_workspace = ws.lower_bound_segment_id.filter(|lb_sidx| {
561+
ws.stacks
562+
.iter()
563+
.flat_map(|s| s.segments.iter().map(|s| s.id))
564+
.any(|sid| sid == *lb_sidx)
565+
});
566+
(ws.id, ws.stacks, md, ws.target, lower_bound_if_in_workspace)
567+
})
542568
})
543569
else {
544570
return Ok(());
@@ -810,6 +836,16 @@ impl Graph {
810836
});
811837
self[sidx].sibling_segment_id = named_segment_id;
812838
}
839+
840+
// The named-segment check is needed as we don't want to double-split unnamed segments.
841+
// What this really does is to pass ownership of the base commit from a named segment to an unnamed one,
842+
// as all algorithms kind of rely on it.
843+
// So if this ever becomes a problem, we can also try to adjust said algorithms downstream.
844+
if let Some(low_bound_segment_id) = ws_low_bound_sidx
845+
&& self[low_bound_segment_id].ref_name.is_some()
846+
{
847+
self.split_segment(low_bound_segment_id, 0, None, Some(refs_by_id), meta)?;
848+
}
813849
Ok(())
814850
}
815851

crates/but-graph/tests/graph/init/with_workspace.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5243,16 +5243,11 @@ fn remote_and_integrated_tracking_branch_on_merge() -> anyhow::Result<()> {
52435243
standard_options().with_extra_target_commit_id(repo.rev_parse_single("origin/main")?),
52445244
)?
52455245
.validated()?;
5246-
// TODO: this shouldn't move past the base on 1ee1e34!
52475246
insta::assert_snapshot!(graph_workspace(&graph.to_workspace()?), @r"
52485247
📕🏘️:0:gitbutler/workspace <> ✓refs/remotes/origin/main⇣1 on 1ee1e34
5249-
└── ≡📙:3:A <> origin/A →:4:⇣1 {1}
5248+
└── ≡📙:3:A <> origin/A →:4:⇣1 on 1ee1e34 {1}
52505249
└── 📙:3:A <> origin/A →:4:⇣1
5251-
├── 🟣2181501
5252-
├── ❄️1ee1e34 (🏘️|✓)
5253-
├── ❄️c822d66 (🏘️|✓)
5254-
├── ❄️bce0c5e (🏘️|✓)
5255-
└── ❄️3183e43 (🏘️|✓)
5250+
└── 🟣2181501
52565251
");
52575252

52585253
Ok(())
@@ -5279,15 +5274,11 @@ fn remote_and_integrated_tracking_branch_on_linear_segment() -> anyhow::Result<(
52795274
standard_options().with_extra_target_commit_id(repo.rev_parse_single("origin/main")?),
52805275
)?
52815276
.validated()?;
5282-
// TODO: Can we arbitrarily split the segment below the low base of all stacks to prevent
5283-
// it from going all the way down?
52845277
insta::assert_snapshot!(graph_workspace(&graph.to_workspace()?), @r"
52855278
📕🏘️:0:gitbutler/workspace <> ✓refs/remotes/origin/main⇣1 on 081bae9
5286-
└── ≡📙:3:A <> origin/A →:4:⇣1 {1}
5279+
└── ≡📙:3:A <> origin/A →:4:⇣1 on 081bae9 {1}
52875280
└── 📙:3:A <> origin/A →:4:⇣1
5288-
├── 🟣197ddce
5289-
├── ❄️081bae9 (🏘️|✓)
5290-
└── ❄️3183e43 (🏘️|✓)
5281+
└── 🟣197ddce
52915282
");
52925283

52935284
Ok(())

0 commit comments

Comments
 (0)