Skip to content

Commit f8752ab

Browse files
committed
Add support for creating dependent branches in workspaces
With and without workspace commits
1 parent 0236892 commit f8752ab

File tree

16 files changed

+839
-350
lines changed

16 files changed

+839
-350
lines changed

crates/but-core/src/ref_metadata.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ impl Workspace {
5858
.iter()
5959
.find_map(|stack| stack.branches.iter().find(|b| b.ref_name.as_ref() == name))
6060
}
61+
62+
/// Find the `(stack_idx, branch_idx)` of `name` within our stack branches and return it,
63+
/// for direct access like `ws.stacks[stack_idx].branches[branch_idx]`.
64+
pub fn find_owner_indexes_by_name(
65+
&self,
66+
name: &gix::refs::FullNameRef,
67+
) -> Option<(usize, usize)> {
68+
self.stacks
69+
.iter()
70+
.enumerate()
71+
.find_map(|(stack_idx, stack)| {
72+
stack.branches.iter().enumerate().find_map(|(seg_idx, b)| {
73+
(b.ref_name.as_ref() == name).then_some((stack_idx, seg_idx))
74+
})
75+
})
76+
}
6177
}
6278

6379
/// Metadata about branches, associated with any Git branch.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod post;
2727
pub struct Overlay {
2828
nonoverriding_references: Vec<gix::refs::Reference>,
2929
meta_branches: Vec<(gix::refs::FullName, ref_metadata::Branch)>,
30+
workspace: Option<(gix::refs::FullName, ref_metadata::Workspace)>,
3031
}
3132

3233
pub(super) type PetGraph = petgraph::stable_graph::StableGraph<Segment, Edge>;

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

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::collections::BTreeSet;
99
impl Overlay {
1010
/// Serve the given `refs` from memory, as if they would exist.
1111
/// This is true only, however, if a real reference doesn't exist.
12-
pub fn with_references_non_overriding(
12+
pub fn with_references_if_new(
1313
mut self,
1414
refs: impl IntoIterator<Item = gix::refs::Reference>,
1515
) -> Self {
@@ -19,13 +19,23 @@ impl Overlay {
1919

2020
/// Serve the given `branches` metadata from memory, as if they would exist,
2121
/// possibly overriding metadata of a ref that already exists.
22-
pub fn with_branch_metadata_overriding(
22+
pub fn with_branch_metadata_override(
2323
mut self,
2424
refs: impl IntoIterator<Item = (gix::refs::FullName, ref_metadata::Branch)>,
2525
) -> Self {
2626
self.meta_branches = refs.into_iter().collect();
2727
self
2828
}
29+
30+
/// Serve the given workspace `metadata` from memory, as if they would exist,
31+
/// possibly overriding metadata of a workspace at that place
32+
pub fn with_workspace_metadata_override(
33+
mut self,
34+
metadata: Option<(gix::refs::FullName, ref_metadata::Workspace)>,
35+
) -> Self {
36+
self.workspace = metadata;
37+
self
38+
}
2939
}
3040

3141
impl Overlay {
@@ -40,6 +50,7 @@ impl Overlay {
4050
let Overlay {
4151
nonoverriding_references,
4252
meta_branches,
53+
workspace,
4354
} = self;
4455
(
4556
OverlayRepo {
@@ -49,6 +60,7 @@ impl Overlay {
4960
OverlayMetadata {
5061
inner: meta,
5162
meta_branches,
63+
workspace,
5264
},
5365
)
5466
}
@@ -209,6 +221,7 @@ impl<'repo> OverlayRepo<'repo> {
209221
pub(crate) struct OverlayMetadata<'meta, T> {
210222
inner: &'meta T,
211223
meta_branches: Vec<(gix::refs::FullName, ref_metadata::Branch)>,
224+
workspace: Option<(gix::refs::FullName, ref_metadata::Workspace)>,
212225
}
213226

214227
impl<T> OverlayMetadata<'_, T>
@@ -226,13 +239,30 @@ where
226239
.ok()
227240
.map(|ws| (ref_name, ws))
228241
})
229-
.map(|(ref_name, ws)| (ref_name, (*ws).clone()))
242+
.map(|(ref_name, ws)| {
243+
if let Some((_ws_ref, ws_override)) = self
244+
.workspace
245+
.as_ref()
246+
.filter(|(ws_ref, _ws_data)| *ws_ref == ref_name)
247+
{
248+
(ref_name, ws_override.clone())
249+
} else {
250+
(ref_name, (*ws).clone())
251+
}
252+
})
230253
}
231254

232255
pub fn workspace_opt(
233256
&self,
234257
ref_name: &gix::refs::FullNameRef,
235258
) -> anyhow::Result<Option<ref_metadata::Workspace>> {
259+
if let Some((_ws_ref, ws_meta)) = self
260+
.workspace
261+
.as_ref()
262+
.filter(|(ws_ref, _ws_meta)| ws_ref.as_ref() == ref_name)
263+
{
264+
return Ok(Some(ws_meta.clone()));
265+
}
236266
let opt = self.inner.workspace_opt(ref_name)?;
237267
Ok(opt.map(|ws_data| ws_data.clone()))
238268
}

crates/but-graph/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ mod debug;
224224
pub type CommitIndex = usize;
225225

226226
/// A graph of connected segments that represent a section of the actual commit-graph.
227-
#[derive(Default, Debug)]
227+
#[derive(Default, Debug, Clone)]
228228
pub struct Graph {
229229
inner: init::PetGraph,
230230
/// From where the graph was created. This is useful if one wants to focus on a subset of the graph.

crates/but-graph/src/projection/workspace.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl Workspace<'_> {
130130
.with_context(|| {
131131
format!(
132132
"Couldn't find any stack that contained the branch named '{}'",
133-
name.as_bstr()
133+
name.shorten()
134134
)
135135
})
136136
}
@@ -159,7 +159,7 @@ impl Workspace<'_> {
159159
.with_context(|| {
160160
format!(
161161
"Couldn't find any stack that contained the branch named '{}'",
162-
name.as_bstr()
162+
name.shorten()
163163
)
164164
})
165165
}
@@ -959,7 +959,7 @@ impl Workspace<'_> {
959959
}
960960

961961
/// Query
962-
impl Workspace<'_> {
962+
impl<'graph> Workspace<'graph> {
963963
/// Return `true` if this workspace is managed, meaning we control certain aspects of it.
964964
/// If `false`, we are more conservative and may not support all features.
965965
pub fn has_managed_ref(&self) -> bool {
@@ -978,8 +978,8 @@ impl Workspace<'_> {
978978
/// Return the name of the workspace reference by looking our segment up in `graph`.
979979
/// Note that for managed workspaces, this can be retrieved via [`WorkspaceKind::Managed`].
980980
/// Note that it can be expected to be set on any workspace, but the data would allow it to not be set.
981-
pub fn ref_name<'a>(&self, graph: &'a Graph) -> Option<&'a gix::refs::FullNameRef> {
982-
graph[self.id].ref_name.as_ref().map(|rn| rn.as_ref())
981+
pub fn ref_name(&self) -> Option<&'graph gix::refs::FullNameRef> {
982+
self.graph[self.id].ref_name.as_ref().map(|rn| rn.as_ref())
983983
}
984984
}
985985

crates/but-graph/src/ref_metadata_legacy.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ impl RefMetadata for VirtualBranchesTomlMetadata {
240240
stack_id = *branch.stack_id.borrow();
241241
} else if stack_id != *branch.stack_id.borrow() {
242242
bail!(
243-
"Inconsistent stack detected, wanted {:?}, but got {:?}",
243+
"{}:Inconsistent stack detected, wanted {:?}, but got {:?}",
244+
branch.ref_name.as_bstr(),
244245
stack_id,
245246
branch.stack_id.borrow()
246247
)

0 commit comments

Comments
 (0)