Update repo scan id when files under dot git dir events
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
d2b18790a0
commit
759b7f1e07
2 changed files with 39 additions and 51 deletions
|
@ -10,7 +10,7 @@ pub struct GitRepository {
|
||||||
// Path to the actual .git folder.
|
// Path to the actual .git folder.
|
||||||
// Note: if .git is a file, this points to the folder indicated by the .git file
|
// Note: if .git is a file, this points to the folder indicated by the .git file
|
||||||
git_dir_path: Arc<Path>,
|
git_dir_path: Arc<Path>,
|
||||||
last_scan_id: usize,
|
scan_id: usize,
|
||||||
libgit_repository: Arc<Mutex<git2::Repository>>,
|
libgit_repository: Arc<Mutex<git2::Repository>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,19 +22,19 @@ impl GitRepository {
|
||||||
Some(Self {
|
Some(Self {
|
||||||
content_path: libgit_repository.workdir()?.into(),
|
content_path: libgit_repository.workdir()?.into(),
|
||||||
git_dir_path: dotgit_path.canonicalize().log_err()?.into(),
|
git_dir_path: dotgit_path.canonicalize().log_err()?.into(),
|
||||||
last_scan_id: 0,
|
scan_id: 0,
|
||||||
libgit_repository: Arc::new(parking_lot::Mutex::new(libgit_repository)),
|
libgit_repository: Arc::new(parking_lot::Mutex::new(libgit_repository)),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_path_managed_by(&self, path: &Path) -> bool {
|
pub fn manages(&self, path: &Path) -> bool {
|
||||||
path.canonicalize()
|
path.canonicalize()
|
||||||
.map(|path| path.starts_with(&self.content_path))
|
.map(|path| path.starts_with(&self.content_path))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_path_in_git_folder(&self, path: &Path) -> bool {
|
pub fn in_dot_git(&self, path: &Path) -> bool {
|
||||||
path.canonicalize()
|
path.canonicalize()
|
||||||
.map(|path| path.starts_with(&self.git_dir_path))
|
.map(|path| path.starts_with(&self.git_dir_path))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
|
@ -48,12 +48,12 @@ impl GitRepository {
|
||||||
self.git_dir_path.as_ref()
|
self.git_dir_path.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_scan_id(&self) -> usize {
|
pub fn scan_id(&self) -> usize {
|
||||||
self.last_scan_id
|
self.scan_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_scan_id(&mut self, scan_id: usize) {
|
pub(super) fn set_scan_id(&mut self, scan_id: usize) {
|
||||||
self.last_scan_id = scan_id;
|
self.scan_id = scan_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_repo<F: FnOnce(&mut git2::Repository)>(&mut self, f: F) {
|
pub fn with_repo<F: FnOnce(&mut git2::Repository)>(&mut self, f: F) {
|
||||||
|
|
|
@ -40,7 +40,6 @@ use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
os::unix::prelude::{OsStrExt, OsStringExt},
|
os::unix::prelude::{OsStrExt, OsStringExt},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -1307,32 +1306,24 @@ impl LocalSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gives the most specific git repository for a given path
|
// Gives the most specific git repository for a given path
|
||||||
pub(crate) fn git_repository_for_file_path(&self, path: &Path) -> Option<GitRepository> {
|
pub(crate) fn repo_for(&self, path: &Path) -> Option<GitRepository> {
|
||||||
self.git_repositories
|
self.git_repositories
|
||||||
.iter()
|
.iter()
|
||||||
.rev() //git_repository is ordered lexicographically
|
.rev() //git_repository is ordered lexicographically
|
||||||
.find(|repo| repo.is_path_managed_by(&self.abs_path.join(path)))
|
.find(|repo| repo.manages(&self.abs_path.join(path)))
|
||||||
.map(|repo| repo.clone())
|
.map(|repo| repo.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ~/zed:
|
pub(crate) fn in_dot_git(&mut self, path: &Path) -> Option<&mut GitRepository> {
|
||||||
// - src
|
|
||||||
// - crates
|
|
||||||
// - .git -> /usr/.git
|
|
||||||
pub(crate) fn git_repository_for_git_data(&self, path: &Path) -> Option<GitRepository> {
|
|
||||||
self.git_repositories
|
self.git_repositories
|
||||||
.iter()
|
.iter_mut()
|
||||||
.find(|repo| repo.is_path_in_git_folder(&self.abs_path.join(path)))
|
.rev() //git_repository is ordered lexicographically
|
||||||
.map(|repo| repo.clone())
|
.find(|repo| repo.in_dot_git(&self.abs_path.join(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn does_git_repository_track_file_path(
|
pub(crate) fn tracks_filepath(&self, repo: &GitRepository, file_path: &Path) -> bool {
|
||||||
&self,
|
|
||||||
repo: &GitRepository,
|
|
||||||
file_path: &Path,
|
|
||||||
) -> bool {
|
|
||||||
// Depends on git_repository_for_file_path returning the most specific git repository for a given path
|
// Depends on git_repository_for_file_path returning the most specific git repository for a given path
|
||||||
self.git_repository_for_file_path(&self.abs_path.join(file_path))
|
self.repo_for(&self.abs_path.join(file_path))
|
||||||
.map_or(false, |r| r.git_dir_path() == repo.git_dir_path())
|
.map_or(false, |r| r.git_dir_path() == repo.git_dir_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2433,6 +2424,11 @@ impl BackgroundScanner {
|
||||||
fs_entry.is_ignored = ignore_stack.is_all();
|
fs_entry.is_ignored = ignore_stack.is_all();
|
||||||
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
||||||
|
|
||||||
|
let scan_id = snapshot.scan_id;
|
||||||
|
if let Some(repo) = snapshot.in_dot_git(&abs_path) {
|
||||||
|
repo.set_scan_id(scan_id);
|
||||||
|
}
|
||||||
|
|
||||||
let mut ancestor_inodes = snapshot.ancestor_inodes_for_path(&path);
|
let mut ancestor_inodes = snapshot.ancestor_inodes_for_path(&path);
|
||||||
if metadata.is_dir && !ancestor_inodes.contains(&metadata.inode) {
|
if metadata.is_dir && !ancestor_inodes.contains(&metadata.inode) {
|
||||||
ancestor_inodes.insert(metadata.inode);
|
ancestor_inodes.insert(metadata.inode);
|
||||||
|
@ -3172,13 +3168,9 @@ mod tests {
|
||||||
tree.read_with(cx, |tree, _cx| {
|
tree.read_with(cx, |tree, _cx| {
|
||||||
let tree = tree.as_local().unwrap();
|
let tree = tree.as_local().unwrap();
|
||||||
|
|
||||||
assert!(tree
|
assert!(tree.repo_for("c.txt".as_ref()).is_none());
|
||||||
.git_repository_for_file_path("c.txt".as_ref())
|
|
||||||
.is_none());
|
|
||||||
|
|
||||||
let repo = tree
|
let repo = tree.repo_for("dir1/src/b.txt".as_ref()).unwrap();
|
||||||
.git_repository_for_file_path("dir1/src/b.txt".as_ref())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
repo.content_path(),
|
repo.content_path(),
|
||||||
|
@ -3189,9 +3181,7 @@ mod tests {
|
||||||
root.path().join("dir1/.git").canonicalize().unwrap()
|
root.path().join("dir1/.git").canonicalize().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let repo = tree
|
let repo = tree.repo_for("dir1/deps/dep1/src/a.txt".as_ref()).unwrap();
|
||||||
.git_repository_for_file_path("dir1/deps/dep1/src/a.txt".as_ref())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
repo.content_path(),
|
repo.content_path(),
|
||||||
|
@ -3204,23 +3194,23 @@ mod tests {
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
let repo = tree
|
let original_scan_id = tree.read_with(cx, |tree, _cx| {
|
||||||
.git_repository_for_git_data("dir1/.git/HEAD".as_ref())
|
let tree = tree.as_local().unwrap();
|
||||||
.unwrap();
|
tree.repo_for("dir1/src/b.txt".as_ref()).unwrap().scan_id()
|
||||||
|
});
|
||||||
|
|
||||||
assert_eq!(
|
std::fs::write(root.path().join("dir1/.git/random_new_file"), "hello").unwrap();
|
||||||
repo.content_path(),
|
tree.flush_fs_events(cx).await;
|
||||||
root.path().join("dir1").canonicalize().unwrap()
|
|
||||||
|
tree.read_with(cx, |tree, _cx| {
|
||||||
|
let tree = tree.as_local().unwrap();
|
||||||
|
let new_scan_id = tree.repo_for("dir1/src/b.txt".as_ref()).unwrap().scan_id();
|
||||||
|
assert_ne!(
|
||||||
|
original_scan_id, new_scan_id,
|
||||||
|
"original {original_scan_id}, new {new_scan_id}"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
repo.git_dir_path(),
|
|
||||||
root.path().join("dir1/.git").canonicalize().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(tree.does_git_repository_track_file_path(&repo, "dir1/src/b.txt".as_ref()));
|
|
||||||
assert!(!tree
|
|
||||||
.does_git_repository_track_file_path(&repo, "dir1/deps/dep1/src/a.txt".as_ref()));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
std::fs::remove_dir_all(root.path().join("dir1/.git")).unwrap();
|
std::fs::remove_dir_all(root.path().join("dir1/.git")).unwrap();
|
||||||
|
@ -3229,9 +3219,7 @@ mod tests {
|
||||||
tree.read_with(cx, |tree, _cx| {
|
tree.read_with(cx, |tree, _cx| {
|
||||||
let tree = tree.as_local().unwrap();
|
let tree = tree.as_local().unwrap();
|
||||||
|
|
||||||
assert!(tree
|
assert!(tree.repo_for("dir1/src/b.txt".as_ref()).is_none());
|
||||||
.git_repository_for_file_path("dir1/src/b.txt".as_ref())
|
|
||||||
.is_none());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue