Skip to content

Commit 5bfbb9a

Browse files
committed
feat: Repository::shallow_commits() returns an uptodate list of shallow boundary commits.
1 parent 3e69535 commit 5bfbb9a

19 files changed

+180
-114
lines changed

gix/src/diff.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
pub use gix_diff::*;
2+
3+
///
4+
pub mod rename {
5+
/// Determine how to do rename tracking.
6+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7+
pub enum Tracking {
8+
/// Do not track renames at all, the fastest option.
9+
Disabled,
10+
/// Track renames.
11+
Renames,
12+
/// Track renames and copies.
13+
///
14+
/// This is the most expensive option.
15+
RenamesAndCopies,
16+
}
17+
}

gix/src/lib.rs

Lines changed: 10 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,7 @@ pub mod interrupt;
9898

9999
mod ext;
100100
///
101-
pub mod prelude {
102-
pub use gix_features::parallel::reduce::Finalize;
103-
pub use gix_odb::{Find, FindExt, Header, HeaderExt, Write};
104-
105-
pub use crate::ext::*;
106-
}
101+
pub mod prelude;
107102

108103
///
109104
pub mod path;
@@ -133,31 +128,10 @@ mod repository;
133128
pub mod tag;
134129

135130
///
136-
pub mod progress {
137-
#[cfg(feature = "progress-tree")]
138-
pub use gix_features::progress::prodash::tree;
139-
pub use gix_features::progress::*;
140-
}
131+
pub mod progress;
141132

142133
///
143-
pub mod diff {
144-
pub use gix_diff::*;
145-
///
146-
pub mod rename {
147-
/// Determine how to do rename tracking.
148-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
149-
pub enum Tracking {
150-
/// Do not track renames at all, the fastest option.
151-
Disabled,
152-
/// Track renames.
153-
Renames,
154-
/// Track renames and copies.
155-
///
156-
/// This is the most expensive option.
157-
RenamesAndCopies,
158-
}
159-
}
160-
}
134+
pub mod diff;
161135

162136
/// See [ThreadSafeRepository::discover()], but returns a [`Repository`] instead.
163137
#[allow(clippy::result_large_err)]
@@ -238,20 +212,10 @@ pub fn open_opts(directory: impl Into<std::path::PathBuf>, options: open::Option
238212
}
239213

240214
///
241-
pub mod permission {
242-
///
243-
pub mod env_var {
244-
///
245-
pub mod resource {
246-
///
247-
pub type Error = gix_sec::permission::Error<std::path::PathBuf>;
248-
}
249-
}
250-
}
215+
pub mod permission;
216+
251217
///
252-
pub mod permissions {
253-
pub use crate::repository::permissions::{Config, Environment};
254-
}
218+
pub mod permissions;
255219
pub use repository::permissions::Permissions;
256220

257221
///
@@ -278,33 +242,10 @@ pub mod remote;
278242
pub mod init;
279243

280244
/// Not to be confused with 'status'.
281-
pub mod state {
282-
/// Tell what operation is currently in progress.
283-
#[derive(Debug, PartialEq, Eq)]
284-
pub enum InProgress {
285-
/// A mailbox is being applied.
286-
ApplyMailbox,
287-
/// A rebase is happening while a mailbox is being applied.
288-
// TODO: test
289-
ApplyMailboxRebase,
290-
/// A git bisect operation has not yet been concluded.
291-
Bisect,
292-
/// A cherry pick operation.
293-
CherryPick,
294-
/// A cherry pick with multiple commits pending.
295-
CherryPickSequence,
296-
/// A merge operation.
297-
Merge,
298-
/// A rebase operation.
299-
Rebase,
300-
/// An interactive rebase operation.
301-
RebaseInteractive,
302-
/// A revert operation.
303-
Revert,
304-
/// A revert operation with multiple commits pending.
305-
RevertSequence,
306-
}
307-
}
245+
pub mod state;
246+
247+
///
248+
pub mod shallow;
308249

309250
///
310251
pub mod discover;

gix/src/open/repository.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ impl ThreadSafeRepository {
267267
// used when spawning new repositories off this one when following worktrees
268268
linked_worktree_options: options,
269269
index: gix_features::fs::MutableSnapshot::new().into(),
270+
shallow_commits: gix_features::fs::MutableSnapshot::new().into(),
270271
})
271272
}
272273
}

gix/src/permission.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
///
2+
pub mod env_var {
3+
///
4+
pub mod resource {
5+
///
6+
pub type Error = gix_sec::permission::Error<std::path::PathBuf>;
7+
}
8+
}

gix/src/permissions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub use crate::repository::permissions::{Config, Environment};

gix/src/prelude.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub use gix_features::parallel::reduce::Finalize;
2+
pub use gix_odb::{Find, FindExt, Header, HeaderExt, Write};
3+
4+
pub use crate::ext::*;

gix/src/progress.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#[cfg(feature = "progress-tree")]
2+
pub use gix_features::progress::prodash::tree;
3+
pub use gix_features::progress::*;

gix/src/repository/impls.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ impl Clone for crate::Repository {
88
self.config.clone(),
99
self.options.clone(),
1010
self.index.clone(),
11+
self.shallow_commits.clone(),
1112
)
1213
}
1314
}
@@ -40,6 +41,7 @@ impl From<&crate::ThreadSafeRepository> for crate::Repository {
4041
repo.config.clone(),
4142
repo.linked_worktree_options.clone(),
4243
repo.index.clone(),
44+
repo.shallow_commits.clone(),
4345
)
4446
}
4547
}
@@ -54,6 +56,7 @@ impl From<crate::ThreadSafeRepository> for crate::Repository {
5456
repo.config,
5557
repo.linked_worktree_options,
5658
repo.index,
59+
repo.shallow_commits,
5760
)
5861
}
5962
}
@@ -68,6 +71,7 @@ impl From<crate::Repository> for crate::ThreadSafeRepository {
6871
config: r.config,
6972
linked_worktree_options: r.options,
7073
index: r.index,
74+
shallow_commits: r.shallow_commits,
7175
}
7276
}
7377
}

gix/src/repository/init.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::cell::RefCell;
22

33
impl crate::Repository {
4+
#[allow(clippy::too_many_arguments)]
45
pub(crate) fn from_refs_and_objects(
56
refs: crate::RefStore,
67
objects: crate::OdbHandle,
@@ -9,6 +10,7 @@ impl crate::Repository {
910
config: crate::config::Cache,
1011
linked_worktree_options: crate::open::Options,
1112
index: crate::worktree::IndexStorage,
13+
shallow_commits: crate::shallow::CommitsStorage,
1214
) -> Self {
1315
let objects = setup_objects(objects, &config);
1416
crate::Repository {
@@ -20,6 +22,7 @@ impl crate::Repository {
2022
config,
2123
options: linked_worktree_options,
2224
index,
25+
shallow_commits,
2326
}
2427
}
2528

gix/src/repository/location.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use std::borrow::Cow;
21
use std::path::PathBuf;
32

4-
use crate::config::tree::{gitoxide, Key};
53
use gix_path::realpath::MAX_SYMLINKS;
64

75
impl crate::Repository {
@@ -43,20 +41,6 @@ impl crate::Repository {
4341
crate::path::install_dir()
4442
}
4543

46-
/// Return the path to the `shallow` file which contains hashes, one per line, that describe commits that don't have their
47-
/// parents within this repository.
48-
pub fn shallow_file(&self) -> PathBuf {
49-
let shallow_name = self
50-
.config
51-
.resolved
52-
.string_filter_by_key(
53-
gitoxide::Core::SHALLOW_FILE.logical_name().as_str(),
54-
&mut self.filter_config_section(),
55-
)
56-
.unwrap_or(Cow::Borrowed("shallow".into()));
57-
self.common_dir().join(gix_path::from_bstr(shallow_name))
58-
}
59-
6044
/// Returns the relative path which is the components between the working tree and the current working dir (CWD).
6145
/// Note that there may be `None` if there is no work tree, even though the `PathBuf` will be empty
6246
/// if the CWD is at the root of the work tree.

gix/src/repository/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(crate) mod permissions;
3030
mod reference;
3131
mod remote;
3232
mod revision;
33+
mod shallow;
3334
mod snapshots;
3435
mod state;
3536
mod thread_safe;

gix/src/repository/shallow.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use crate::bstr::ByteSlice;
2+
use crate::config::tree::{gitoxide, Key};
3+
use crate::Repository;
4+
use std::borrow::Cow;
5+
use std::path::PathBuf;
6+
7+
impl Repository {
8+
/// Return `true` if the repository is a shallow clone, i.e. contains history only up to a certain depth.
9+
pub fn is_shallow(&self) -> bool {
10+
self.shallow_file()
11+
.metadata()
12+
.map_or(false, |m| m.is_file() && m.len() > 0)
13+
}
14+
15+
/// Return a shared list of shallow commits which is updated automatically if the in-memory snapshot has become stale as the underlying file
16+
/// on disk has changed.
17+
///
18+
/// The shared list is shared across all clones of this repository.
19+
pub fn shallow_commits(&self) -> Result<Option<crate::shallow::Commits>, crate::shallow::open::Error> {
20+
self.shallow_commits.recent_snapshot(
21+
|| self.shallow_file().metadata().ok().and_then(|m| m.modified().ok()),
22+
|| {
23+
let buf = match std::fs::read(self.shallow_file()) {
24+
Ok(buf) => buf,
25+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
26+
Err(err) => return Err(err.into()),
27+
};
28+
29+
let commits = buf
30+
.lines()
31+
.map(gix_hash::ObjectId::from_hex)
32+
.collect::<Result<Vec<_>, _>>()?;
33+
34+
if commits.is_empty() {
35+
Ok(None)
36+
} else {
37+
Ok(Some(commits))
38+
}
39+
},
40+
)
41+
}
42+
43+
/// Return the path to the `shallow` file which contains hashes, one per line, that describe commits that don't have their
44+
/// parents within this repository.
45+
///
46+
/// Note that it may not exist if the repository isn't actually shallow.
47+
pub fn shallow_file(&self) -> PathBuf {
48+
let shallow_name = self
49+
.config
50+
.resolved
51+
.string_filter_by_key(
52+
gitoxide::Core::SHALLOW_FILE.logical_name().as_str(),
53+
&mut self.filter_config_section(),
54+
)
55+
.unwrap_or_else(|| Cow::Borrowed("shallow".into()));
56+
self.common_dir().join(gix_path::from_bstr(shallow_name))
57+
}
58+
}

gix/src/repository/state.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,4 @@ impl crate::Repository {
4141
None
4242
}
4343
}
44-
45-
/// Return `true` if the repository is a shallow clone, i.e. contains history only up to a certain depth.
46-
pub fn is_shallow(&self) -> bool {
47-
self.shallow_file()
48-
.metadata()
49-
.map_or(false, |m| m.is_file() && m.len() > 0)
50-
}
5144
}

gix/src/shallow.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
pub(crate) type CommitsStorage =
2+
gix_features::threading::OwnShared<gix_features::fs::MutableSnapshot<Vec<gix_hash::ObjectId>>>;
3+
/// A lazily loaded and auto-updated list of commits which are at the shallow boundary (behind which there are no commits available),
4+
/// sorted to allow bisecting.
5+
pub type Commits = gix_features::fs::SharedSnapshot<Vec<gix_hash::ObjectId>>;
6+
7+
///
8+
pub mod open {
9+
/// The error returned by [`Repository::shallow_commits()`][crate::Repository::shallow_commits()].
10+
#[derive(Debug, thiserror::Error)]
11+
#[allow(missing_docs)]
12+
pub enum Error {
13+
#[error("Could not open shallow file for reading")]
14+
Io(#[from] std::io::Error),
15+
#[error("Could not decode a line in shallow file as hex-encoded object hash")]
16+
DecodeHash(#[from] gix_hash::decode::Error),
17+
}
18+
}

gix/src/state.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// Tell what operation is currently in progress.
2+
#[derive(Debug, PartialEq, Eq)]
3+
pub enum InProgress {
4+
/// A mailbox is being applied.
5+
ApplyMailbox,
6+
/// A rebase is happening while a mailbox is being applied.
7+
// TODO: test
8+
ApplyMailboxRebase,
9+
/// A git bisect operation has not yet been concluded.
10+
Bisect,
11+
/// A cherry pick operation.
12+
CherryPick,
13+
/// A cherry pick with multiple commits pending.
14+
CherryPickSequence,
15+
/// A merge operation.
16+
Merge,
17+
/// A rebase operation.
18+
Rebase,
19+
/// An interactive rebase operation.
20+
RebaseInteractive,
21+
/// A revert operation.
22+
Revert,
23+
/// A revert operation with multiple commits pending.
24+
RevertSequence,
25+
}

gix/src/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ pub struct Repository {
152152
/// Particularly useful when following linked worktrees and instantiating new equally configured worktree repositories.
153153
pub(crate) options: crate::open::Options,
154154
pub(crate) index: crate::worktree::IndexStorage,
155+
pub(crate) shallow_commits: crate::shallow::CommitsStorage,
155156
}
156157

157158
/// An instance with access to everything a git repository entails, best imagined as container implementing `Sync + Send` for _most_
@@ -175,6 +176,7 @@ pub struct ThreadSafeRepository {
175176
pub(crate) linked_worktree_options: crate::open::Options,
176177
/// The index of this instances worktree.
177178
pub(crate) index: crate::worktree::IndexStorage,
179+
pub(crate) shallow_commits: crate::shallow::CommitsStorage,
178180
}
179181

180182
/// A remote which represents a way to interact with hosts for remote clones of the parent repository.

gix/tests/repository/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod object;
55
mod open;
66
mod reference;
77
mod remote;
8+
mod shallow;
89
mod state;
910
mod worktree;
1011

0 commit comments

Comments
 (0)