Skip to content

Commit 0b3eb14

Browse files
committed
fix: assure the correct repository is used for checkouts after clone. (#1129)
If this is not the case, it's possible for filters to run in the context of potential parent repositories, which then can have all kinds of issues. In case of `git-lfs`, for instance, it would try to download objects from the wrong repository.
1 parent 3b71ca5 commit 0b3eb14

File tree

9 files changed

+82
-11
lines changed

9 files changed

+82
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ worktree-mutation = ["attributes", "dep:gix-worktree-state"]
8181
excludes = ["dep:gix-ignore", "dep:gix-worktree", "index"]
8282

8383
## Query attributes and excludes. Enables access to pathspecs, worktree checkouts, filter-pipelines and submodules.
84-
attributes = ["excludes", "dep:gix-filter", "dep:gix-pathspec", "dep:gix-attributes", "dep:gix-submodule", "gix-worktree?/attributes"]
84+
attributes = ["excludes", "dep:gix-filter", "dep:gix-pathspec", "dep:gix-attributes", "dep:gix-submodule", "gix-worktree?/attributes", "dep:gix-command"]
8585

8686
## Add support for mailmaps, as way of determining the final name of commmiters and authors.
8787
mailmap = ["dep:gix-mailmap"]
@@ -254,6 +254,7 @@ gix-commitgraph = { version = "^0.22.0", path = "../gix-commitgraph" }
254254
gix-pathspec = { version = "^0.4.0", path = "../gix-pathspec", optional = true }
255255
gix-submodule = { version = "^0.5.0", path = "../gix-submodule", optional = true }
256256
gix-status = { version = "^0.2.0", path = "../gix-status", optional = true }
257+
gix-command = { version = "^0.2.10", path = "../gix-command", optional = true }
257258

258259
gix-worktree-stream = { version = "^0.6.0", path = "../gix-worktree-stream", optional = true }
259260
gix-archive = { version = "^0.6.0", path = "../gix-archive", default-features = false, optional = true }

gix/src/config/cache/access.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,11 @@ impl Cache {
197197
let capabilities = self.fs_capabilities()?;
198198
let filters = {
199199
let collection = Default::default();
200-
let mut filters = gix_filter::Pipeline::new(&collection, crate::filter::Pipeline::options(repo)?);
200+
let mut filters = gix_filter::Pipeline::new(
201+
&collection,
202+
repo.command_context()?,
203+
crate::filter::Pipeline::options(repo)?,
204+
);
201205
if let Ok(mut head) = repo.head() {
202206
let ctx = filters.driver_context_mut();
203207
ctx.ref_name = head.referent_name().map(|name| name.as_bstr().to_owned());

gix/src/config/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ pub mod checkout_options {
152152
Attributes(#[from] super::attribute_stack::Error),
153153
#[error(transparent)]
154154
FilterPipelineOptions(#[from] crate::filter::pipeline::options::Error),
155+
#[error(transparent)]
156+
CommandContext(#[from] crate::config::command_context::Error),
157+
}
158+
}
159+
160+
///
161+
#[cfg(feature = "attributes")]
162+
pub mod command_context {
163+
use crate::config;
164+
165+
/// The error produced when collecting all information relevant to spawned commands,
166+
/// obtained via [Repository::command_context()](crate::Repository::command_context()).
167+
#[derive(Debug, thiserror::Error)]
168+
#[allow(missing_docs)]
169+
pub enum Error {
170+
#[error(transparent)]
171+
PathSpec(#[from] gix_pathspec::defaults::from_environment::Error),
172+
#[error(transparent)]
173+
Boolean(#[from] config::boolean::Error),
155174
}
156175
}
157176

@@ -544,3 +563,22 @@ pub(crate) struct Cache {
544563
environment: crate::open::permissions::Environment,
545564
// TODO: make core.precomposeUnicode available as well.
546565
}
566+
567+
/// Utillities shared privately across the crate, for lack of a better place.
568+
pub(crate) mod shared {
569+
use crate::config;
570+
use crate::config::cache::util::ApplyLeniency;
571+
use crate::config::tree::Core;
572+
573+
pub fn is_replace_refs_enabled(
574+
config: &gix_config::File<'static>,
575+
lenient: bool,
576+
mut filter_config_section: fn(&gix_config::file::Metadata) -> bool,
577+
) -> Result<Option<bool>, config::boolean::Error> {
578+
config
579+
.boolean_filter_by_key("core.useReplaceRefs", &mut filter_config_section)
580+
.map(|b| Core::USE_REPLACE_REFS.enrich_error(b))
581+
.transpose()
582+
.with_leniency(lenient)
583+
}
584+
}

gix/src/filter.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub mod pipeline {
3232
name: BString,
3333
source: gix_config::value::Error,
3434
},
35+
#[error(transparent)]
36+
CommandContext(#[from] config::command_context::Error),
3537
}
3638
}
3739

@@ -111,7 +113,11 @@ impl<'repo> Pipeline<'repo> {
111113
/// Create a new instance by extracting all necessary information and configuration from a `repo` along with `cache` for accessing
112114
/// attributes. The `index` is used for some filters which may access it under very specific circumstances.
113115
pub fn new(repo: &'repo Repository, cache: gix_worktree::Stack) -> Result<Self, pipeline::options::Error> {
114-
let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), Self::options(repo)?);
116+
let pipeline = gix_filter::Pipeline::new(
117+
cache.attributes_collection(),
118+
repo.command_context()?,
119+
Self::options(repo)?,
120+
);
115121
Ok(Pipeline {
116122
inner: pipeline,
117123
cache,

gix/src/open/repository.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use super::{Error, Options};
88
use crate::{
99
config,
1010
config::{
11-
cache::{interpolate_context, util::ApplyLeniency},
11+
cache::interpolate_context,
1212
tree::{gitoxide, Core, Key, Safe},
1313
},
1414
open::Permissions,
@@ -324,11 +324,7 @@ fn replacement_objects_refs_prefix(
324324
lenient: bool,
325325
mut filter_config_section: fn(&gix_config::file::Metadata) -> bool,
326326
) -> Result<Option<PathBuf>, Error> {
327-
let is_disabled = config
328-
.boolean_filter_by_key("core.useReplaceRefs", &mut filter_config_section)
329-
.map(|b| Core::USE_REPLACE_REFS.enrich_error(b))
330-
.transpose()
331-
.with_leniency(lenient)
327+
let is_disabled = config::shared::is_replace_refs_enabled(config, lenient, filter_config_section)
332328
.map_err(config::Error::ConfigBoolean)?
333329
.unwrap_or(true);
334330

gix/src/repository/config/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,26 @@ impl crate::Repository {
7979
Ok(opts)
8080
}
8181

82+
/// Return the context to be passed to any spawned program that is supposed to interact with the repository, like
83+
/// hooks or filters.
84+
#[cfg(feature = "attributes")]
85+
pub fn command_context(&self) -> Result<gix_command::Context, config::command_context::Error> {
86+
Ok(gix_command::Context {
87+
git_dir: self.git_dir().to_owned().into(),
88+
worktree_dir: self.work_dir().map(ToOwned::to_owned),
89+
no_replace_objects: config::shared::is_replace_refs_enabled(
90+
&self.config.resolved,
91+
self.config.lenient_config,
92+
self.filter_config_section(),
93+
)?
94+
.map(|enabled| !enabled),
95+
ref_namespace: None,
96+
literal_pathspecs: None,
97+
glob_pathspecs: None,
98+
icase_pathspecs: None,
99+
})
100+
}
101+
82102
/// The kind of object hash the repository is configured to use.
83103
pub fn object_hash(&self) -> gix_hash::Kind {
84104
self.config.object_hash

gix/src/repository/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ pub mod worktree_stream {
124124
AttributesCache(#[from] crate::config::attribute_stack::Error),
125125
#[error(transparent)]
126126
FilterPipeline(#[from] crate::filter::pipeline::options::Error),
127+
#[error(transparent)]
128+
CommandContext(#[from] crate::config::command_context::Error),
127129
#[error("Needed {id} to be a tree to turn into a workspace stream, got {actual}")]
128130
NotATree {
129131
id: gix_hash::ObjectId,

gix/src/repository/worktree.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ impl crate::Repository {
7979
let mut cache = self
8080
.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?
8181
.detach();
82-
let pipeline =
83-
gix_filter::Pipeline::new(cache.attributes_collection(), crate::filter::Pipeline::options(self)?);
82+
let pipeline = gix_filter::Pipeline::new(
83+
cache.attributes_collection(),
84+
self.command_context()?,
85+
crate::filter::Pipeline::options(self)?,
86+
);
8487
let objects = self.objects.clone().into_arc().expect("TBD error handling");
8588
let stream = gix_worktree_stream::from_tree(
8689
id,

0 commit comments

Comments
 (0)