Skip to content

Commit 7eef949

Browse files
committed
feat: add Repository::index_or_load_from_head_or_empty().
It's useful to get a reasonable index in any case, even on unborn repositories. It's for cases where the `HEAD` isn't setup at all, despite content being available, and to avoid unnecessary restrictions on what works.
1 parent e66ab89 commit 7eef949

File tree

7 files changed

+77
-10
lines changed

7 files changed

+77
-10
lines changed

gix/src/repository/diff.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl Repository {
1919
mode: gix_diff::blob::pipeline::Mode,
2020
worktree_roots: gix_diff::blob::pipeline::WorktreeRoots,
2121
) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
22-
let index = self.index_or_load_from_head()?;
22+
let index = self.index_or_load_from_head_or_empty()?;
2323
Ok(crate::diff::resource_cache(
2424
self,
2525
mode,

gix/src/repository/index.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ impl crate::Repository {
9696
///
9797
/// ### Note
9898
///
99-
/// The locally stored index is not guaranteed to represent `HEAD^{tree}` if this repository is bare - bare repos
100-
/// don't naturally have an index and if an index is present it must have been generated by hand.
99+
/// * The locally stored index is not guaranteed to represent `HEAD^{tree}` if this repository is bare - bare repos
100+
/// don't naturally have an index and if an index is present it must have been generated by hand.
101+
/// * This method will fail on unborn repositories as `HEAD` doesn't point to a reference yet, which is needed to resolve
102+
/// the revspec. If that is a concern, use [`Self::index_or_load_from_head_or_empty()`] instead.
101103
pub fn index_or_load_from_head(
102104
&self,
103105
) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head::Error> {
@@ -110,6 +112,29 @@ impl crate::Repository {
110112
})
111113
}
112114

115+
/// Open the persisted worktree index or generate it from the current `HEAD^{tree}` to live in-memory only,
116+
/// or resort to an empty index if `HEAD` is unborn.
117+
///
118+
/// Use this method to get an index in any repository, even bare ones that don't have one naturally, or those
119+
/// that are in a state where `HEAD` is invalid or points to an unborn reference.
120+
pub fn index_or_load_from_head_or_empty(
121+
&self,
122+
) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head_or_empty::Error> {
123+
Ok(match self.try_index()? {
124+
Some(index) => IndexPersistedOrInMemory::Persisted(index),
125+
None => match self.head()?.id() {
126+
Some(id) => {
127+
let head_tree_id = id.object()?.peel_to_commit()?.tree_id()?;
128+
IndexPersistedOrInMemory::InMemory(self.index_from_tree(&head_tree_id)?)
129+
}
130+
None => IndexPersistedOrInMemory::InMemory(gix_index::File::from_state(
131+
gix_index::State::new(self.object_hash()),
132+
self.index_path(),
133+
)),
134+
},
135+
})
136+
}
137+
113138
/// Create new index-file, which would live at the correct location, in memory from the given `tree`.
114139
///
115140
/// Note that this is an expensive operation as it requires recursively traversing the entire tree to unpack it into the index.

gix/src/repository/merge.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Repository {
1818
&self,
1919
worktree_roots: gix_merge::blob::pipeline::WorktreeRoots,
2020
) -> Result<gix_merge::blob::Platform, merge_resource_cache::Error> {
21-
let index = self.index_or_load_from_head()?;
21+
let index = self.index_or_load_from_head_or_empty()?;
2222
let mode = {
2323
let renormalize = self
2424
.config

gix/src/repository/mod.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub mod merge_resource_cache {
100100
#[error(transparent)]
101101
PipelineOptions(#[from] crate::config::merge::pipeline_options::Error),
102102
#[error(transparent)]
103-
Index(#[from] crate::repository::index_or_load_from_head::Error),
103+
Index(#[from] crate::repository::index_or_load_from_head_or_empty::Error),
104104
#[error(transparent)]
105105
AttributeStack(#[from] crate::config::attribute_stack::Error),
106106
#[error(transparent)]
@@ -154,7 +154,7 @@ pub mod diff_resource_cache {
154154
#[error("Could not obtain resource cache for diffing")]
155155
ResourceCache(#[from] crate::diff::resource_cache::Error),
156156
#[error(transparent)]
157-
Index(#[from] crate::repository::index_or_load_from_head::Error),
157+
Index(#[from] crate::repository::index_or_load_from_head_or_empty::Error),
158158
#[error(transparent)]
159159
AttributeStack(#[from] crate::config::attribute_stack::Error),
160160
}
@@ -289,7 +289,7 @@ pub mod pathspec_defaults_ignore_case {
289289
///
290290
#[cfg(feature = "index")]
291291
pub mod index_or_load_from_head {
292-
/// The error returned by [`Repository::index_or_load_from_head()`][crate::Repository::index_or_load_from_head()].
292+
/// The error returned by [`Repository::index_or_load_from_head()`](crate::Repository::index_or_load_from_head()).
293293
#[derive(thiserror::Error, Debug)]
294294
#[allow(missing_docs)]
295295
pub enum Error {
@@ -304,10 +304,32 @@ pub mod index_or_load_from_head {
304304
}
305305
}
306306

307+
///
308+
#[cfg(feature = "index")]
309+
pub mod index_or_load_from_head_or_empty {
310+
/// The error returned by [`Repository::index_or_load_from_head_or_empty()`](crate::Repository::index_or_load_from_head_or_empty()).
311+
#[derive(thiserror::Error, Debug)]
312+
#[allow(missing_docs)]
313+
pub enum Error {
314+
#[error(transparent)]
315+
ReadHead(#[from] crate::reference::find::existing::Error),
316+
#[error(transparent)]
317+
FindCommit(#[from] crate::object::find::existing::Error),
318+
#[error(transparent)]
319+
PeelToTree(#[from] crate::object::peel::to_kind::Error),
320+
#[error(transparent)]
321+
TreeId(#[from] gix_object::decode::Error),
322+
#[error(transparent)]
323+
TraverseTree(#[from] crate::repository::index_from_tree::Error),
324+
#[error(transparent)]
325+
OpenIndex(#[from] crate::worktree::open_index::Error),
326+
}
327+
}
328+
307329
///
308330
#[cfg(feature = "worktree-stream")]
309331
pub mod worktree_stream {
310-
/// The error returned by [`Repository::worktree_stream()`][crate::Repository::worktree_stream()].
332+
/// The error returned by [`Repository::worktree_stream()`](crate::Repository::worktree_stream()).
311333
#[derive(Debug, thiserror::Error)]
312334
#[allow(missing_docs)]
313335
pub enum Error {
@@ -332,6 +354,6 @@ pub mod worktree_stream {
332354
///
333355
#[cfg(feature = "worktree-archive")]
334356
pub mod worktree_archive {
335-
/// The error returned by [`Repository::worktree_archive()`][crate::Repository::worktree_archive()].
357+
/// The error returned by [`Repository::worktree_archive()`](crate::Repository::worktree_archive()).
336358
pub type Error = gix_archive::Error;
337359
}
Binary file not shown.

gix/tests/fixtures/make_basic_repo.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,6 @@ git init empty-core-excludes
4141
git clone --bare . non-bare-without-worktree
4242
(cd non-bare-without-worktree
4343
git config core.bare false
44-
)
44+
)
45+
46+
git init unborn;

gix/tests/gix/repository/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ mod state;
1717
mod submodule;
1818
mod worktree;
1919

20+
#[cfg(feature = "index")]
21+
mod index {
22+
#[test]
23+
fn basics() -> crate::Result {
24+
let repo = crate::named_subrepo_opts("make_basic_repo.sh", "unborn", gix::open::Options::isolated())?;
25+
assert!(
26+
repo.index_or_load_from_head().is_err(),
27+
"can't read index if `HEAD^{{tree}}` can't be resolved"
28+
);
29+
assert!(
30+
repo.index_or_load_from_head_or_empty()?.entries().is_empty(),
31+
"an empty index is created on the fly"
32+
);
33+
Ok(())
34+
}
35+
}
36+
2037
#[cfg(feature = "dirwalk")]
2138
mod dirwalk {
2239
use gix_dir::entry::Kind::*;
@@ -44,6 +61,7 @@ mod dirwalk {
4461
("non-bare-repo-without-index".into(), Repository),
4562
("non-bare-without-worktree".into(), Directory),
4663
("some".into(), Directory),
64+
("unborn".into(), Repository),
4765
];
4866
assert_eq!(
4967
collect

0 commit comments

Comments
 (0)