Skip to content

Commit 444714d

Browse files
committed
feat: add Repository::is_dirty()
The simplest way to learn if the repository is dirty or not.
1 parent fc9039a commit 444714d

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

gix/src/status/mod.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,52 @@ impl Repository {
8383
}
8484
}
8585

86+
///
87+
#[cfg(feature = "parallel")]
88+
pub mod is_dirty {
89+
use crate::Repository;
90+
91+
/// The error returned by [Repository::is_dirty()].
92+
#[derive(Debug, thiserror::Error)]
93+
#[allow(missing_docs)]
94+
pub enum Error {
95+
#[error(transparent)]
96+
StatusPlatform(#[from] crate::config::boolean::Error),
97+
#[error(transparent)]
98+
CreateStatusIterator(#[from] crate::status::index_worktree::iter::Error),
99+
}
100+
101+
impl Repository {
102+
/// Returns `true` if the repository is dirty.
103+
/// This means it's changed in one of the following ways:
104+
///
105+
/// * the index was changed in comparison to its working tree
106+
/// * the working tree was changed in comparison to the index
107+
/// * submodules are taken in consideration, along with their `ignore` and `isActive` configuration
108+
///
109+
/// Note that *untracked files* do *not* affect this flag.
110+
///
111+
/// ### Incomplete Implementation Warning
112+
///
113+
/// Currently, this does not compute changes between the head and the index.
114+
// TODO: use iterator which also tests for head->index changes.
115+
pub fn is_dirty(&self) -> Result<bool, Error> {
116+
let is_dirty = self
117+
.status(gix_features::progress::Discard)?
118+
.index_worktree_rewrites(None)
119+
.index_worktree_submodules(crate::status::Submodule::AsConfigured { check_dirty: true })
120+
.index_worktree_options_mut(|opts| {
121+
opts.dirwalk_options = None;
122+
})
123+
.into_index_worktree_iter(Vec::new())?
124+
.take_while(Result::is_ok)
125+
.next()
126+
.is_some();
127+
Ok(is_dirty)
128+
}
129+
}
130+
}
131+
86132
mod platform;
87133

88134
///
Binary file not shown.

gix/tests/fixtures/make_submodules.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ git init -q module1
1010
git commit -q -m c1
1111
echo hello >> this
1212
git commit -q -am c2
13+
touch untracked
1314
)
1415

1516
git init submodule-head-changed

gix/tests/status/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,45 @@ mod index_worktree {
4444
}
4545
}
4646
}
47+
48+
mod is_dirty {
49+
use crate::status::repo;
50+
51+
#[test]
52+
fn various_changes_positive() -> crate::Result {
53+
let repo = repo("modified-untracked-and-submodule-head-changed-and-modified")?;
54+
assert!(repo.is_dirty()?, "The repository has various changes");
55+
Ok(())
56+
}
57+
58+
#[test]
59+
fn submodule_changes_are_picked_up() -> crate::Result {
60+
let repo = repo("submodule-head-changed")?;
61+
assert!(repo.is_dirty()?, "head-changes are also discoverd");
62+
Ok(())
63+
}
64+
65+
#[test]
66+
fn untracked_files_are_excluded() -> crate::Result {
67+
let repo = repo("module1")?;
68+
assert_eq!(
69+
repo.status(gix::progress::Discard)?
70+
.into_index_worktree_iter(Vec::new())?
71+
.count(),
72+
1,
73+
"there is one untracked file"
74+
);
75+
assert!(
76+
!repo.is_dirty()?,
77+
"untracked files aren't taken into consideration, just like `git describe` which ignores them"
78+
);
79+
Ok(())
80+
}
81+
82+
#[test]
83+
fn no_changes() -> crate::Result {
84+
let repo = repo("with-submodules")?;
85+
assert!(!repo.is_dirty()?, "there are no changes");
86+
Ok(())
87+
}
88+
}

0 commit comments

Comments
 (0)