Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/but-graph/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ pub struct Overlay {
entrypoint: Entrypoint,
nonoverriding_references: Vec<gix::refs::Reference>,
overriding_references: Vec<gix::refs::Reference>,
/// A list of references that should not be picked up anymore in the
/// re-traversal.
///
/// For example, if the `but_rebase::graph_rebase::Editor` converts a
/// `Reference` step to a `None` step which is the equivalent of running
/// `git update-ref -d`, it should no longer be part of the [`Graph`], so we
/// would list the particular reference as a dropped reference.
dropped_references: Vec<gix::refs::FullName>,
Comment thread
Caleb-T-Owens marked this conversation as resolved.
meta_branches: Vec<(gix::refs::FullName, ref_metadata::Branch)>,
workspace: Option<(gix::refs::FullName, ref_metadata::Workspace)>,
}
Expand Down
69 changes: 54 additions & 15 deletions crates/but-graph/src/init/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,34 @@ impl Overlay {
self
}

/// A list of references that should not be picked up anymore in the
/// re-traversal.
///
/// For example, if the `but_rebase::graph_rebase::Editor` converts a
/// `Reference` step to a `None` step which is the equivalent of running
/// `git update-ref -d`, it should no longer be part of the
/// [`crate::Graph`], so we would list the particular reference as a dropped
/// reference.
pub fn with_dropped_references(
mut self,
refs: impl IntoIterator<Item = gix::refs::FullName>,
) -> Self {
self.dropped_references.extend(refs);
self
}

/// Override the starting position of the traversal by setting it to `id`,
/// and optionally, by providing the `ref_name` that points to `id`.
pub fn with_entrypoint(
mut self,
id: gix::ObjectId,
ref_name: Option<gix::refs::FullName>,
) -> Self {
if let Some((_id, ref_name)) = self.entrypoint {
self.overriding_references
.retain(|r| Some(&r.name) != ref_name.as_ref())
}

if let Some(ref_name) = &ref_name {
self.overriding_references.push(gix::refs::Reference {
name: ref_name.to_owned(),
Expand Down Expand Up @@ -84,20 +105,30 @@ impl Overlay {
let Overlay {
nonoverriding_references,
overriding_references,
dropped_references,
meta_branches,
workspace,
entrypoint,
} = self;
// Construct BTreeMaps with a deterministic order from left to right.
let mut or = BTreeMap::new();
for reference in overriding_references {
if !or.contains_key(&reference.name) {
or.insert(reference.name.clone(), reference);
}
}
let mut nor = BTreeMap::new();
for reference in nonoverriding_references {
if !nor.contains_key(&reference.name) {
nor.insert(reference.name.clone(), reference);
}
}
Comment thread
Caleb-T-Owens marked this conversation as resolved.

(
OverlayRepo {
nonoverriding_references: nonoverriding_references
.into_iter()
.map(|r| (r.name.clone(), r))
.collect(),
overriding_references: overriding_references
.into_iter()
.map(|r| (r.name.clone(), r))
.collect(),
nonoverriding_references: nor,
overriding_references: or,
dropped_references: dropped_references.into_iter().collect(),
inner: repo,
},
OverlayMetadata {
Expand All @@ -116,6 +147,7 @@ pub(crate) struct OverlayRepo<'repo> {
inner: &'repo gix::Repository,
nonoverriding_references: NameToReference,
overriding_references: NameToReference,
dropped_references: BTreeSet<gix::refs::FullName>,
}

/// Note that functions with `'repo` in their return value technically leak the bare repo, and it's
Expand All @@ -129,7 +161,9 @@ impl<'repo> OverlayRepo<'repo> {
&self,
ref_name: &gix::refs::FullNameRef,
) -> anyhow::Result<Option<gix::Reference<'repo>>> {
if let Some(r) = self.overriding_references.get(ref_name) {
if self.dropped_references.contains(ref_name) {
Ok(None)
} else if let Some(r) = self.overriding_references.get(ref_name) {
Ok(Some(r.clone().attach(self.inner)))
} else if let Some(rn) = self.inner.try_find_reference(ref_name)? {
Ok(Some(rn))
Expand All @@ -144,6 +178,11 @@ impl<'repo> OverlayRepo<'repo> {
&self,
ref_name: &gix::refs::FullNameRef,
) -> anyhow::Result<gix::Reference<'repo>> {
if self.dropped_references.contains(ref_name) {
bail!(
"Failed to find reference {ref_name} due to it being dropped in the traversal overlay"
);
}
if let Some(r) = self.overriding_references.get(ref_name) {
return Ok(r.clone().attach(self.inner));
}
Expand Down Expand Up @@ -211,9 +250,13 @@ impl<'repo> OverlayRepo<'repo> {
prefixes: impl Iterator<Item = &'a str>,
workspace_ref_names: &[&gix::refs::FullNameRef],
) -> anyhow::Result<RefsById> {
let mut seen = (!self.nonoverriding_references.is_empty()).then(BTreeSet::new);
let mut seen = BTreeSet::new();
let mut ref_filter =
|r: gix::Reference<'_>| -> Option<(gix::ObjectId, gix::refs::FullName)> {
if self.dropped_references.contains(r.name()) {
return None;
}

if workspace_ref_names.contains(&r.name()) {
return None;
}
Expand All @@ -226,11 +269,7 @@ impl<'repo> OverlayRepo<'repo> {
(id.detach(), r.inner.name)
};
// This is only for overrides.
Comment thread
Caleb-T-Owens marked this conversation as resolved.
if let Some(seen) = seen.as_mut() {
seen.insert(name.clone()).then_some((id, name))
} else {
Some((id, name))
}
seen.insert(name.clone()).then_some((id, name))
};
let mut all_refs_by_id = gix::hashtable::HashMap::<_, Vec<_>>::default();
for prefix in prefixes {
Expand Down
1 change: 1 addition & 0 deletions crates/but-graph/tests/graph/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ fn commit_with_two_parents() -> anyhow::Result<()> {
Ok(())
}

mod overlay;
mod with_workspace;

pub(crate) mod utils;
Expand Down
Loading
Loading