mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Enhance git change detection by introducing relevant prefixes
- Updated the `git_changed_files_impl` and `collect_untracked_files` functions to accept a set of relevant prefixes, allowing for more targeted change detection. - Modified the `collect_index_worktree_changes` function to filter changes based on the provided prefixes, improving efficiency in identifying tracked and untracked files. - Added a new `known_paths` method to the `RojoTree` struct to facilitate the extraction of relevant directory paths. These changes aim to optimize the detection of changes in the git repository by focusing on specified directory prefixes.
This commit is contained in:
parent
6ed6d15a69
commit
33022667dc
3 changed files with 70 additions and 16 deletions
76
src/git.rs
76
src/git.rs
|
|
@ -75,6 +75,7 @@ fn resolve_tree_id(repo: &gix::Repository, rev: &str) -> Option<gix::ObjectId> {
|
||||||
fn git_changed_files_impl(
|
fn git_changed_files_impl(
|
||||||
repo: &gix::Repository,
|
repo: &gix::Repository,
|
||||||
initial_head: Option<&str>,
|
initial_head: Option<&str>,
|
||||||
|
relevant_prefixes: &HashSet<PathBuf>,
|
||||||
) -> Option<ChangedFiles> {
|
) -> Option<ChangedFiles> {
|
||||||
let mut tracked = HashSet::new();
|
let mut tracked = HashSet::new();
|
||||||
let mut untracked = HashSet::new();
|
let mut untracked = HashSet::new();
|
||||||
|
|
@ -123,7 +124,7 @@ fn git_changed_files_impl(
|
||||||
|
|
||||||
let t = Instant::now();
|
let t = Instant::now();
|
||||||
let before = tracked.len();
|
let before = tracked.len();
|
||||||
collect_index_worktree_changes(repo, &index, &mut tracked);
|
collect_index_worktree_changes(repo, &index, &mut tracked, relevant_prefixes);
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"[TIMING] compute_git_metadata: collect_index_worktree_changes {}ms ({} entries, {} worktree-dirty)",
|
"[TIMING] compute_git_metadata: collect_index_worktree_changes {}ms ({} entries, {} worktree-dirty)",
|
||||||
t.elapsed().as_millis(),
|
t.elapsed().as_millis(),
|
||||||
|
|
@ -137,7 +138,7 @@ fn git_changed_files_impl(
|
||||||
}
|
}
|
||||||
let t = Instant::now();
|
let t = Instant::now();
|
||||||
let before = tracked.len();
|
let before = tracked.len();
|
||||||
collect_index_worktree_changes(repo, &index, &mut tracked);
|
collect_index_worktree_changes(repo, &index, &mut tracked, relevant_prefixes);
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"[TIMING] compute_git_metadata: collect_index_worktree_changes (no tree) {}ms ({} entries, {} worktree-dirty)",
|
"[TIMING] compute_git_metadata: collect_index_worktree_changes (no tree) {}ms ({} entries, {} worktree-dirty)",
|
||||||
t.elapsed().as_millis(),
|
t.elapsed().as_millis(),
|
||||||
|
|
@ -147,7 +148,7 @@ fn git_changed_files_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
let t = Instant::now();
|
let t = Instant::now();
|
||||||
collect_untracked_files(repo, &mut untracked);
|
collect_untracked_files(repo, &mut untracked, relevant_prefixes);
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"[TIMING] compute_git_metadata: collect_untracked_files {}ms ({} found)",
|
"[TIMING] compute_git_metadata: collect_untracked_files {}ms ({} found)",
|
||||||
t.elapsed().as_millis(),
|
t.elapsed().as_millis(),
|
||||||
|
|
@ -252,6 +253,7 @@ fn collect_index_worktree_changes(
|
||||||
repo: &gix::Repository,
|
repo: &gix::Repository,
|
||||||
index: &gix::index::File,
|
index: &gix::index::File,
|
||||||
tracked: &mut HashSet<PathBuf>,
|
tracked: &mut HashSet<PathBuf>,
|
||||||
|
relevant_prefixes: &HashSet<PathBuf>,
|
||||||
) {
|
) {
|
||||||
let work_dir = match repo.workdir() {
|
let work_dir = match repo.workdir() {
|
||||||
Some(d) => d.to_owned(),
|
Some(d) => d.to_owned(),
|
||||||
|
|
@ -272,6 +274,18 @@ fn collect_index_worktree_changes(
|
||||||
for entry in index.entries() {
|
for entry in index.entries() {
|
||||||
let path_bstr = entry.path(index);
|
let path_bstr = entry.path(index);
|
||||||
let path_str = path_bstr.to_str_lossy();
|
let path_str = path_bstr.to_str_lossy();
|
||||||
|
|
||||||
|
if !relevant_prefixes.is_empty() {
|
||||||
|
let rel = Path::new(path_str.as_ref());
|
||||||
|
let parent = rel.parent().unwrap_or(Path::new(""));
|
||||||
|
if !relevant_prefixes
|
||||||
|
.iter()
|
||||||
|
.any(|prefix| parent.starts_with(prefix) || prefix.starts_with(parent))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let full_path = work_dir.join(path_str.as_ref());
|
let full_path = work_dir.join(path_str.as_ref());
|
||||||
|
|
||||||
match gix::index::fs::Metadata::from_path_no_follow(&full_path) {
|
match gix::index::fs::Metadata::from_path_no_follow(&full_path) {
|
||||||
|
|
@ -304,7 +318,11 @@ fn collect_index_worktree_changes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_untracked_files(repo: &gix::Repository, untracked: &mut HashSet<PathBuf>) {
|
fn collect_untracked_files(
|
||||||
|
repo: &gix::Repository,
|
||||||
|
untracked: &mut HashSet<PathBuf>,
|
||||||
|
relevant_prefixes: &HashSet<PathBuf>,
|
||||||
|
) {
|
||||||
let work_dir = match repo.workdir() {
|
let work_dir = match repo.workdir() {
|
||||||
Some(d) => d.to_owned(),
|
Some(d) => d.to_owned(),
|
||||||
None => return,
|
None => return,
|
||||||
|
|
@ -378,8 +396,17 @@ fn collect_untracked_files(repo: &gix::Repository, untracked: &mut HashSet<PathB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !relevant_prefixes.is_empty() {
|
||||||
|
for prefix in relevant_prefixes {
|
||||||
|
let dir = work_dir.join(prefix);
|
||||||
|
if dir.is_dir() {
|
||||||
|
walk_dir(&work_dir, &dir, &index, &tracked_dirs, untracked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
walk_dir(&work_dir, &work_dir, &index, &tracked_dirs, untracked);
|
walk_dir(&work_dir, &work_dir, &index, &tracked_dirs, untracked);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_object_ref(repo: &gix::Repository, object_ref: &str) -> Option<String> {
|
fn resolve_object_ref(repo: &gix::Repository, object_ref: &str) -> Option<String> {
|
||||||
if let Some(path) = object_ref.strip_prefix(":0:") {
|
if let Some(path) = object_ref.strip_prefix(":0:") {
|
||||||
|
|
@ -786,7 +813,26 @@ pub fn compute_git_metadata(
|
||||||
);
|
);
|
||||||
|
|
||||||
let t = Instant::now();
|
let t = Instant::now();
|
||||||
let changed_files = match git_changed_files_impl(&repo, initial_head) {
|
let relevant_prefixes: HashSet<PathBuf> = {
|
||||||
|
let tree = tree_handle.lock().unwrap();
|
||||||
|
let mut dirs = HashSet::new();
|
||||||
|
for abs_path in tree.known_paths() {
|
||||||
|
if let Ok(rel) = abs_path.strip_prefix(repo_root) {
|
||||||
|
if let Some(parent) = rel.parent() {
|
||||||
|
dirs.insert(parent.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirs
|
||||||
|
};
|
||||||
|
log::trace!(
|
||||||
|
"[TIMING] compute_git_metadata: extract_relevant_prefixes {}ms ({} dirs)",
|
||||||
|
t.elapsed().as_millis(),
|
||||||
|
relevant_prefixes.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let t = Instant::now();
|
||||||
|
let changed_files = match git_changed_files_impl(&repo, initial_head, &relevant_prefixes) {
|
||||||
Some(files) => files,
|
Some(files) => files,
|
||||||
None => {
|
None => {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
|
|
@ -1145,7 +1191,7 @@ mod tests {
|
||||||
git_commit_all(dir.path(), "init");
|
git_commit_all(dir.path(), "init");
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None);
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new());
|
||||||
assert!(changed.is_some());
|
assert!(changed.is_some());
|
||||||
assert!(changed.unwrap().is_empty());
|
assert!(changed.unwrap().is_empty());
|
||||||
}
|
}
|
||||||
|
|
@ -1159,7 +1205,7 @@ mod tests {
|
||||||
fs::write(dir.path().join("script.luau"), "modified").unwrap();
|
fs::write(dir.path().join("script.luau"), "modified").unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(changed.tracked.contains(&PathBuf::from("script.luau")));
|
assert!(changed.tracked.contains(&PathBuf::from("script.luau")));
|
||||||
assert!(changed.untracked.is_empty());
|
assert!(changed.untracked.is_empty());
|
||||||
}
|
}
|
||||||
|
|
@ -1174,7 +1220,7 @@ mod tests {
|
||||||
git_stage(dir.path(), "script.luau");
|
git_stage(dir.path(), "script.luau");
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(changed.tracked.contains(&PathBuf::from("script.luau")));
|
assert!(changed.tracked.contains(&PathBuf::from("script.luau")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1187,7 +1233,7 @@ mod tests {
|
||||||
fs::write(dir.path().join("new_file.luau"), "new").unwrap();
|
fs::write(dir.path().join("new_file.luau"), "new").unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(changed.untracked.contains(&PathBuf::from("new_file.luau")));
|
assert!(changed.untracked.contains(&PathBuf::from("new_file.luau")));
|
||||||
assert!(!changed.tracked.contains(&PathBuf::from("new_file.luau")));
|
assert!(!changed.tracked.contains(&PathBuf::from("new_file.luau")));
|
||||||
}
|
}
|
||||||
|
|
@ -1201,7 +1247,7 @@ mod tests {
|
||||||
fs::remove_file(dir.path().join("to_delete.luau")).unwrap();
|
fs::remove_file(dir.path().join("to_delete.luau")).unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(changed.tracked.contains(&PathBuf::from("to_delete.luau")));
|
assert!(changed.tracked.contains(&PathBuf::from("to_delete.luau")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1217,7 +1263,7 @@ mod tests {
|
||||||
fs::write(dir.path().join("untracked.luau"), "brand new").unwrap();
|
fs::write(dir.path().join("untracked.luau"), "brand new").unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
let all = changed.all();
|
let all = changed.all();
|
||||||
assert!(all.contains(&PathBuf::from("will_modify.luau")));
|
assert!(all.contains(&PathBuf::from("will_modify.luau")));
|
||||||
assert!(all.contains(&PathBuf::from("untracked.luau")));
|
assert!(all.contains(&PathBuf::from("untracked.luau")));
|
||||||
|
|
@ -1233,7 +1279,7 @@ mod tests {
|
||||||
fs::write(dir.path().join("new.luau"), "content").unwrap();
|
fs::write(dir.path().join("new.luau"), "content").unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None);
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new());
|
||||||
assert!(changed.is_some());
|
assert!(changed.is_some());
|
||||||
assert!(changed
|
assert!(changed
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -1251,7 +1297,7 @@ mod tests {
|
||||||
fs::write(dir.path().join("src/module.luau"), "modified").unwrap();
|
fs::write(dir.path().join("src/module.luau"), "modified").unwrap();
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
let changed = git_changed_files_impl(&repo, None).unwrap();
|
let changed = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(changed.tracked.contains(&PathBuf::from("src/module.luau")));
|
assert!(changed.tracked.contains(&PathBuf::from("src/module.luau")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1269,13 +1315,13 @@ mod tests {
|
||||||
|
|
||||||
let repo = open_repo(dir.path()).unwrap();
|
let repo = open_repo(dir.path()).unwrap();
|
||||||
|
|
||||||
let without = git_changed_files_impl(&repo, None).unwrap();
|
let without = git_changed_files_impl(&repo, None, &HashSet::new()).unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
!without.all().contains(&PathBuf::from("script.luau")),
|
!without.all().contains(&PathBuf::from("script.luau")),
|
||||||
"without initial_head, committed file should NOT appear"
|
"without initial_head, committed file should NOT appear"
|
||||||
);
|
);
|
||||||
|
|
||||||
let with = git_changed_files_impl(&repo, Some(&initial_head)).unwrap();
|
let with = git_changed_files_impl(&repo, Some(&initial_head), &HashSet::new()).unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
with.tracked.contains(&PathBuf::from("script.luau")),
|
with.tracked.contains(&PathBuf::from("script.luau")),
|
||||||
"with initial_head, committed file should appear"
|
"with initial_head, committed file should appear"
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,10 @@ impl<K: Hash + Eq, V: Eq> MultiMap<K, V> {
|
||||||
bucket.push(v);
|
bucket.push(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> hash_map::Keys<'_, K, Vec<V>> {
|
||||||
|
self.inner.keys()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove<Q: Borrow<K>, U: Borrow<V>>(&mut self, k: Q, v: U) -> Option<V> {
|
pub fn remove<Q: Borrow<K>, U: Borrow<V>>(&mut self, k: Q, v: U) -> Option<V> {
|
||||||
let b = v.borrow();
|
let b = v.borrow();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,10 @@ impl RojoTree {
|
||||||
self.path_to_ids.get(path)
|
self.path_to_ids.get(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn known_paths(&self) -> impl Iterator<Item = &PathBuf> {
|
||||||
|
self.path_to_ids.keys()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_metadata(&self, id: Ref) -> Option<&InstanceMetadata> {
|
pub fn get_metadata(&self, id: Ref) -> Option<&InstanceMetadata> {
|
||||||
self.metadata_map.get(&id)
|
self.metadata_map.get(&id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue