git: Support git repos with .git folder above project root (#11550)
TODOs: - [x] Add assertions to the test to ensure that the git status is propagated - [x] Get collaboration working - [x] Test opening a git repository inside another git repository - [x] Test opening the sub-folder of a repository that itself contains another git repository in a subfolder Fixes: - Fixes https://github.com/zed-industries/zed/issues/10154 - Fixes https://github.com/zed-industries/zed/issues/8418 - Fixes https://github.com/zed-industries/zed/issues/8275 - Fixes https://github.com/zed-industries/zed/issues/7816 - Fixes https://github.com/zed-industries/zed/issues/6762 - Fixes https://github.com/zed-industries/zed/issues/4419 - Fixes https://github.com/zed-industries/zed/issues/4672 - Fixes https://github.com/zed-industries/zed/issues/5161 Release Notes: - Added support for opening subfolders of git repositories and treating them as part of a repository (show git status in project panel, show git diff in gutter, git blame works, ...) ([#4672](https://github.com/zed-industries/zed/issues/4672)). Demo video: https://github.com/zed-industries/zed/assets/1185253/afc1cdc3-372c-404e-99ea-15708589251c
This commit is contained in:
parent
9f0a20241b
commit
db89353193
3 changed files with 331 additions and 72 deletions
|
@ -2240,8 +2240,9 @@ async fn test_git_status(cx: &mut TestAppContext) {
|
|||
tree.read_with(cx, |tree, _cx| {
|
||||
let snapshot = tree.snapshot();
|
||||
assert_eq!(snapshot.repositories().count(), 1);
|
||||
let (dir, _) = snapshot.repositories().next().unwrap();
|
||||
let (dir, repo_entry) = snapshot.repositories().next().unwrap();
|
||||
assert_eq!(dir.as_ref(), Path::new("project"));
|
||||
assert!(repo_entry.location_in_repo.is_none());
|
||||
|
||||
assert_eq!(
|
||||
snapshot.status_for_file(project_path.join(B_TXT)),
|
||||
|
@ -2369,6 +2370,96 @@ async fn test_git_status(cx: &mut TestAppContext) {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_repository_subfolder_git_status(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let root = temp_tree(json!({
|
||||
"my-repo": {
|
||||
// .git folder will go here
|
||||
"a.txt": "a",
|
||||
"sub-folder-1": {
|
||||
"sub-folder-2": {
|
||||
"c.txt": "cc",
|
||||
"d": {
|
||||
"e.txt": "eee"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
}));
|
||||
|
||||
const C_TXT: &str = "sub-folder-1/sub-folder-2/c.txt";
|
||||
const E_TXT: &str = "sub-folder-1/sub-folder-2/d/e.txt";
|
||||
|
||||
// Set up git repository before creating the worktree.
|
||||
let git_repo_work_dir = root.path().join("my-repo");
|
||||
let repo = git_init(git_repo_work_dir.as_path());
|
||||
git_add(C_TXT, &repo);
|
||||
git_commit("Initial commit", &repo);
|
||||
|
||||
// Open the worktree in subfolder
|
||||
let project_root = Path::new("my-repo/sub-folder-1/sub-folder-2");
|
||||
let tree = Worktree::local(
|
||||
build_client(cx),
|
||||
root.path().join(project_root),
|
||||
true,
|
||||
Arc::new(RealFs::default()),
|
||||
Default::default(),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tree.flush_fs_events(cx).await;
|
||||
tree.flush_fs_events_in_root_git_repository(cx).await;
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
// Ensure that the git status is loaded correctly
|
||||
tree.read_with(cx, |tree, _cx| {
|
||||
let snapshot = tree.snapshot();
|
||||
assert_eq!(snapshot.repositories().count(), 1);
|
||||
let (dir, repo_entry) = snapshot.repositories().next().unwrap();
|
||||
// Path is blank because the working directory of
|
||||
// the git repository is located at the root of the project
|
||||
assert_eq!(dir.as_ref(), Path::new(""));
|
||||
|
||||
// This is the missing path between the root of the project (sub-folder-2) and its
|
||||
// location relative to the root of the repository.
|
||||
assert_eq!(
|
||||
repo_entry.location_in_repo,
|
||||
Some(Arc::from(Path::new("sub-folder-1/sub-folder-2")))
|
||||
);
|
||||
|
||||
assert_eq!(snapshot.status_for_file("c.txt"), None);
|
||||
assert_eq!(
|
||||
snapshot.status_for_file("d/e.txt"),
|
||||
Some(GitFileStatus::Added)
|
||||
);
|
||||
});
|
||||
|
||||
// Now we simulate FS events, but ONLY in the .git folder that's outside
|
||||
// of out project root.
|
||||
// Meaning: we don't produce any FS events for files inside the project.
|
||||
git_add(E_TXT, &repo);
|
||||
git_commit("Second commit", &repo);
|
||||
tree.flush_fs_events_in_root_git_repository(cx).await;
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
tree.read_with(cx, |tree, _cx| {
|
||||
let snapshot = tree.snapshot();
|
||||
|
||||
assert!(snapshot.repositories().next().is_some());
|
||||
|
||||
assert_eq!(snapshot.status_for_file("c.txt"), None);
|
||||
assert_eq!(snapshot.status_for_file("d/e.txt"), None);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_propagate_git_statuses(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue