From 3129e3dcf563e22f04e41576ca3e85c9567525c1 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 7 Mar 2025 10:51:46 -0700 Subject: [PATCH] Remove worktree and project notifies (#26244) This reduces the number of multibuffer syncs from 100,000 to 20,000. Before this change each editor individually observed the project, so literally any project change was amplified by the number of editors you had open. Now editors listen to their buffers instead of the project, and other users of `cx.observe` on the project have been updated to use specific events to reduce churn. Follow up to #26237 Release Notes: - Improved performance of Zed in large repos with lots of file system events. --------- Co-authored-by: Max Brunsfeld (cherry picked from commit 80fb88520f0c52b806ac963dca6a39bead1f49aa) --- .../src/activity_indicator.rs | 24 ++++- .../src/context_store.rs | 95 ++++++++++--------- crates/editor/src/editor.rs | 16 +--- crates/multi_buffer/src/multi_buffer.rs | 2 + crates/project/src/environment.rs | 18 +++- crates/project/src/lsp_store.rs | 69 +++++++------- crates/project/src/project.rs | 33 ++----- crates/title_bar/src/title_bar.rs | 2 +- crates/workspace/src/item.rs | 1 + crates/workspace/src/workspace.rs | 2 - crates/worktree/src/worktree.rs | 35 ++++--- crates/worktree/src/worktree_tests.rs | 57 ++++++----- 12 files changed, 189 insertions(+), 165 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 7a86e5019642b4e91c320f6d07392ecd0120af5a..105bcff8db096b4e0772fe29b12f750cf5dc9656 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -9,7 +9,10 @@ use gpui::{ }; use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId}; use lsp::LanguageServerName; -use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId}; +use project::{ + EnvironmentErrorMessage, LanguageServerProgress, LspStoreEvent, Project, + ProjectEnvironmentEvent, WorktreeId, +}; use smallvec::SmallVec; use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration}; use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip}; @@ -73,7 +76,22 @@ impl ActivityIndicator { }) .detach(); - cx.observe(&project, |_, _, cx| cx.notify()).detach(); + cx.subscribe( + &project.read(cx).lsp_store(), + |_, _, event, cx| match event { + LspStoreEvent::LanguageServerUpdate { .. } => cx.notify(), + _ => {} + }, + ) + .detach(); + + cx.subscribe( + &project.read(cx).environment().clone(), + |_, _, event, cx| match event { + ProjectEnvironmentEvent::ErrorsUpdated => cx.notify(), + }, + ) + .detach(); if let Some(auto_updater) = auto_updater.as_ref() { cx.observe(auto_updater, |_, _, cx| cx.notify()).detach(); @@ -204,7 +222,7 @@ impl ActivityIndicator { message: error.0.clone(), on_click: Some(Arc::new(move |this, window, cx| { this.project.update(cx, |project, cx| { - project.remove_environment_error(cx, worktree_id); + project.remove_environment_error(worktree_id, cx); }); window.dispatch_action(Box::new(workspace::OpenLog), cx); })), diff --git a/crates/assistant_context_editor/src/context_store.rs b/crates/assistant_context_editor/src/context_store.rs index cda9f68ea7bf6940ab3a39f0ff165e11819a75f6..557b6d3e6eb48eff22d316b939706d13249dbc34 100644 --- a/crates/assistant_context_editor/src/context_store.rs +++ b/crates/assistant_context_editor/src/context_store.rs @@ -104,49 +104,53 @@ impl ContextStore { const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100); let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await; - let this = cx.new(|cx: &mut Context| { - let context_server_factory_registry = - ContextServerFactoryRegistry::default_global(cx); - let context_server_manager = cx.new(|cx| { - ContextServerManager::new(context_server_factory_registry, project.clone(), cx) - }); - let mut this = Self { - contexts: Vec::new(), - contexts_metadata: Vec::new(), - context_server_manager, - context_server_slash_command_ids: HashMap::default(), - host_contexts: Vec::new(), - fs, - languages, - slash_commands, - telemetry, - _watch_updates: cx.spawn(|this, mut cx| { - async move { - while events.next().await.is_some() { - this.update(&mut cx, |this, cx| this.reload(cx))? - .await - .log_err(); + let this = + cx.new(|cx: &mut Context| { + let context_server_factory_registry = + ContextServerFactoryRegistry::default_global(cx); + let context_server_manager = cx.new(|cx| { + ContextServerManager::new( + context_server_factory_registry, + project.clone(), + cx, + ) + }); + let mut this = Self { + contexts: Vec::new(), + contexts_metadata: Vec::new(), + context_server_manager, + context_server_slash_command_ids: HashMap::default(), + host_contexts: Vec::new(), + fs, + languages, + slash_commands, + telemetry, + _watch_updates: cx.spawn(|this, mut cx| { + async move { + while events.next().await.is_some() { + this.update(&mut cx, |this, cx| this.reload(cx))? + .await + .log_err(); + } + anyhow::Ok(()) } - anyhow::Ok(()) - } - .log_err() - }), - client_subscription: None, - _project_subscriptions: vec![ - cx.observe(&project, Self::handle_project_changed), - cx.subscribe(&project, Self::handle_project_event), - ], - project_is_shared: false, - client: project.read(cx).client(), - project: project.clone(), - prompt_builder, - }; - this.handle_project_changed(project.clone(), cx); - this.synchronize_contexts(cx); - this.register_context_server_handlers(cx); - this.reload(cx).detach_and_log_err(cx); - this - })?; + .log_err() + }), + client_subscription: None, + _project_subscriptions: vec![ + cx.subscribe(&project, Self::handle_project_event) + ], + project_is_shared: false, + client: project.read(cx).client(), + project: project.clone(), + prompt_builder, + }; + this.handle_project_shared(project.clone(), cx); + this.synchronize_contexts(cx); + this.register_context_server_handlers(cx); + this.reload(cx).detach_and_log_err(cx); + this + })?; Ok(this) }) @@ -288,7 +292,7 @@ impl ContextStore { })? } - fn handle_project_changed(&mut self, _: Entity, cx: &mut Context) { + fn handle_project_shared(&mut self, _: Entity, cx: &mut Context) { let is_shared = self.project.read(cx).is_shared(); let was_shared = mem::replace(&mut self.project_is_shared, is_shared); if is_shared == was_shared { @@ -318,11 +322,14 @@ impl ContextStore { fn handle_project_event( &mut self, - _: Entity, + project: Entity, event: &project::Event, cx: &mut Context, ) { match event { + project::Event::RemoteIdChanged(_) => { + self.handle_project_shared(project, cx); + } project::Event::Reshared => { self.advertise_contexts(cx); } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index c355747ee2c3f17ae9748d330347e0489a3836e4..b8a665f80e5774d3a978d0ead81f4058fbad404a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1248,11 +1248,6 @@ impl Editor { let mut project_subscriptions = Vec::new(); if mode == EditorMode::Full { if let Some(project) = project.as_ref() { - if buffer.read(cx).is_singleton() { - project_subscriptions.push(cx.observe_in(project, window, |_, _, _, cx| { - cx.emit(EditorEvent::TitleChanged); - })); - } project_subscriptions.push(cx.subscribe_in( project, window, @@ -15349,14 +15344,9 @@ impl Editor { } multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged), multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved), - multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => { - cx.emit(EditorEvent::TitleChanged) - } - // multi_buffer::Event::DiffBaseChanged => { - // self.scrollbar_marker_state.dirty = true; - // cx.emit(EditorEvent::DiffBaseChanged); - // cx.notify(); - // } + multi_buffer::Event::FileHandleChanged + | multi_buffer::Event::Reloaded + | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged), multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed), multi_buffer::Event::DiagnosticsUpdated => { self.refresh_active_diagnostics(cx); diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 2d14a50870ef0029939ff60d54a67e2d07562b4b..14f52e9b2418e8c9cffc74955251288b1d380928 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -121,6 +121,7 @@ pub enum Event { Discarded, DirtyChanged, DiagnosticsUpdated, + BufferDiffChanged, } /// A diff hunk, representing a range of consequent lines in a multibuffer. @@ -253,6 +254,7 @@ impl DiffState { if let Some(changed_range) = changed_range.clone() { this.buffer_diff_changed(diff, changed_range, cx) } + cx.emit(Event::BufferDiffChanged); } BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx), _ => {} diff --git a/crates/project/src/environment.rs b/crates/project/src/environment.rs index 9a5aa9fba14245e63f44f77d2840e9a70722cf52..ad550ce0d92c8f016601957b98d28bff4d1921b4 100644 --- a/crates/project/src/environment.rs +++ b/crates/project/src/environment.rs @@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc}; use util::ResultExt; use collections::HashMap; -use gpui::{App, AppContext as _, Context, Entity, Task}; +use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task}; use settings::Settings as _; use worktree::WorktreeId; @@ -19,6 +19,12 @@ pub struct ProjectEnvironment { environment_error_messages: HashMap, } +pub enum ProjectEnvironmentEvent { + ErrorsUpdated, +} + +impl EventEmitter for ProjectEnvironment {} + impl ProjectEnvironment { pub fn new( worktree_store: &Entity, @@ -65,8 +71,13 @@ impl ProjectEnvironment { self.environment_error_messages.iter() } - pub(crate) fn remove_environment_error(&mut self, worktree_id: WorktreeId) { + pub(crate) fn remove_environment_error( + &mut self, + worktree_id: WorktreeId, + cx: &mut Context, + ) { self.environment_error_messages.remove(&worktree_id); + cx.emit(ProjectEnvironmentEvent::ErrorsUpdated); } /// Returns the project environment, if possible. @@ -158,8 +169,9 @@ impl ProjectEnvironment { } if let Some(error) = error_message { - this.update(&mut cx, |this, _| { + this.update(&mut cx, |this, cx| { this.environment_error_messages.insert(worktree_id, error); + cx.emit(ProjectEnvironmentEvent::ErrorsUpdated) }) .log_err(); } diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 0a73c90d18a1563d2cc5c7ee626559418ad1e77a..dd1d1b978f63a994449b705ea839b4e433735bcd 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -6679,33 +6679,19 @@ impl LspStore { cx, ); } - lsp::WorkDoneProgress::Report(report) => { - if self.on_lsp_work_progress( - language_server_id, - token.clone(), - LanguageServerProgress { - title: None, - is_disk_based_diagnostics_progress, - is_cancellable: report.cancellable.unwrap_or(false), - message: report.message.clone(), - percentage: report.percentage.map(|p| p as usize), - last_update_at: cx.background_executor().now(), - }, - cx, - ) { - cx.emit(LspStoreEvent::LanguageServerUpdate { - language_server_id, - message: proto::update_language_server::Variant::WorkProgress( - proto::LspWorkProgress { - token, - message: report.message, - percentage: report.percentage, - is_cancellable: report.cancellable, - }, - ), - }) - } - } + lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress( + language_server_id, + token, + LanguageServerProgress { + title: None, + is_disk_based_diagnostics_progress, + is_cancellable: report.cancellable.unwrap_or(false), + message: report.message, + percentage: report.percentage.map(|p| p as usize), + last_update_at: cx.background_executor().now(), + }, + cx, + ), lsp::WorkDoneProgress::End(_) => { language_server_status.progress_tokens.remove(&token); self.on_lsp_work_end(language_server_id, token.clone(), cx); @@ -6745,13 +6731,13 @@ impl LspStore { token: String, progress: LanguageServerProgress, cx: &mut Context, - ) -> bool { + ) { + let mut did_update = false; if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) { - match status.pending_work.entry(token) { + match status.pending_work.entry(token.clone()) { btree_map::Entry::Vacant(entry) => { - entry.insert(progress); - cx.notify(); - return true; + entry.insert(progress.clone()); + did_update = true; } btree_map::Entry::Occupied(mut entry) => { let entry = entry.get_mut(); @@ -6760,7 +6746,7 @@ impl LspStore { { entry.last_update_at = progress.last_update_at; if progress.message.is_some() { - entry.message = progress.message; + entry.message = progress.message.clone(); } if progress.percentage.is_some() { entry.percentage = progress.percentage; @@ -6768,14 +6754,25 @@ impl LspStore { if progress.is_cancellable != entry.is_cancellable { entry.is_cancellable = progress.is_cancellable; } - cx.notify(); - return true; + did_update = true; } } } } - false + if did_update { + cx.emit(LspStoreEvent::LanguageServerUpdate { + language_server_id, + message: proto::update_language_server::Variant::WorkProgress( + proto::LspWorkProgress { + token, + message: progress.message, + percentage: progress.percentage.map(|p| p as u32), + is_cancellable: Some(progress.is_cancellable), + }, + ), + }) + } } fn on_lsp_work_end( diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b44410c36f498c11a1668d84fc075f8eff91deb5..54cbdd4d0311301622247e4ae09b495456ea3ac1 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -23,7 +23,7 @@ mod project_tests; mod direnv; mod environment; use buffer_diff::BufferDiff; -pub use environment::EnvironmentErrorMessage; +pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent}; use git::Repository; pub mod search_history; mod yarn; @@ -836,7 +836,6 @@ impl Project { }); cx.subscribe(&ssh, Self::on_ssh_event).detach(); - cx.observe(&ssh, |_, _, cx| cx.notify()).detach(); let this = Self { buffer_ordered_messages_tx: tx, @@ -1321,9 +1320,9 @@ impl Project { self.environment.read(cx).environment_errors() } - pub fn remove_environment_error(&mut self, cx: &mut Context, worktree_id: WorktreeId) { - self.environment.update(cx, |environment, _| { - environment.remove_environment_error(worktree_id); + pub fn remove_environment_error(&mut self, worktree_id: WorktreeId, cx: &mut Context) { + self.environment.update(cx, |environment, cx| { + environment.remove_environment_error(worktree_id, cx); }); } @@ -1714,7 +1713,6 @@ impl Project { }; cx.emit(Event::RemoteIdChanged(Some(project_id))); - cx.notify(); Ok(()) } @@ -1730,7 +1728,6 @@ impl Project { self.worktree_store.update(cx, |worktree_store, cx| { worktree_store.send_project_updates(cx); }); - cx.notify(); cx.emit(Event::Reshared); Ok(()) } @@ -1760,13 +1757,12 @@ impl Project { self.enqueue_buffer_ordered_message(BufferOrderedMessage::Resync) .unwrap(); cx.emit(Event::Rejoined); - cx.notify(); Ok(()) } pub fn unshare(&mut self, cx: &mut Context) -> Result<()> { self.unshare_internal(cx)?; - cx.notify(); + cx.emit(Event::RemoteIdChanged(None)); Ok(()) } @@ -1810,7 +1806,6 @@ impl Project { } self.disconnected_from_host_internal(cx); cx.emit(Event::DisconnectedFromHost); - cx.notify(); } pub fn set_role(&mut self, role: proto::ChannelRole, cx: &mut Context) { @@ -2459,15 +2454,11 @@ impl Project { } } - fn on_worktree_added(&mut self, worktree: &Entity, cx: &mut Context) { - { - let mut remotely_created_models = self.remotely_created_models.lock(); - if remotely_created_models.retain_count > 0 { - remotely_created_models.worktrees.push(worktree.clone()) - } + fn on_worktree_added(&mut self, worktree: &Entity, _: &mut Context) { + let mut remotely_created_models = self.remotely_created_models.lock(); + if remotely_created_models.retain_count > 0 { + remotely_created_models.worktrees.push(worktree.clone()) } - cx.observe(worktree, |_, _, cx| cx.notify()).detach(); - cx.notify(); } fn on_worktree_released(&mut self, id_to_remove: WorktreeId, cx: &mut Context) { @@ -2479,8 +2470,6 @@ impl Project { }) .log_err(); } - - cx.notify(); } fn on_buffer_event( @@ -3714,7 +3703,6 @@ impl Project { cx.emit(Event::CollaboratorJoined(collaborator.peer_id)); this.collaborators .insert(collaborator.peer_id, collaborator); - cx.notify(); })?; Ok(()) @@ -3758,7 +3746,6 @@ impl Project { old_peer_id, new_peer_id, }); - cx.notify(); Ok(()) })? } @@ -3786,7 +3773,6 @@ impl Project { }); cx.emit(Event::CollaboratorLeft(peer_id)); - cx.notify(); Ok(()) })? } @@ -4202,7 +4188,6 @@ impl Project { worktrees: Vec, cx: &mut Context, ) -> Result<()> { - cx.notify(); self.worktree_store.update(cx, |worktree_store, cx| { worktree_store.set_worktrees_from_proto(worktrees, self.replica_id(), cx) }) diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index f0f186f570ae1be84196e9dc9e46e56856f89dc1..de514d1339a91e4064af725d30951d142c889354 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -307,7 +307,7 @@ impl TitleBar { cx.notify() }), ); - subscriptions.push(cx.observe(&project, |_, _, cx| cx.notify())); + subscriptions.push(cx.subscribe(&project, |_, _, _, cx| cx.notify())); subscriptions.push(cx.observe(&active_call, |this, _, cx| this.active_call_changed(cx))); subscriptions.push(cx.observe_window_activation(window, Self::window_activation_changed)); subscriptions.push(cx.observe(&user_store, |_, _, cx| cx.notify())); diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 83eb5d27c588b6ec1752eb22b0273cd2de7ed3ff..8bf0691c7543ea8e728f32c56ba26a8ad7423329 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -852,6 +852,7 @@ impl ItemHandle for Entity { .detach(); let item_id = self.item_id(); + workspace.update_item_dirty_state(self, window, cx); cx.observe_release_in(self, window, move |workspace, _, _, _| { workspace.panes_by_item.remove(&item_id); event_subscription.take(); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 6ac97d50455f428d13c8cbe31e709451a2f7e5bf..2b51bfbfad461082db54ec35fb56dc10fe368aba 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -879,8 +879,6 @@ impl Workspace { window: &mut Window, cx: &mut Context, ) -> Self { - cx.observe_in(&project, window, |_, _, _, cx| cx.notify()) - .detach(); cx.subscribe_in(&project, window, move |this, _, event, window, cx| { match event { project::Event::RemoteIdChanged(_) => { diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 1e7b585ae5e9eb3f02c8092db26cd66432d46f16..8afc0f1b61b47f5ca9cc7ffb34dfc486d58655dc 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -1569,7 +1569,6 @@ impl LocalWorktree { this.update_abs_path_and_refresh(new_path, cx); } } - cx.notify(); }) .ok(); } @@ -5897,14 +5896,21 @@ impl WorktreeModelHandle for Entity { .await .unwrap(); - cx.condition(&tree, |tree, _| tree.entry_for_path(file_name).is_some()) - .await; + let mut events = cx.events(&tree); + while events.next().await.is_some() { + if tree.update(cx, |tree, _| tree.entry_for_path(file_name).is_some()) { + break; + } + } fs.remove_file(&root_path.join(file_name), Default::default()) .await .unwrap(); - cx.condition(&tree, |tree, _| tree.entry_for_path(file_name).is_none()) - .await; + while events.next().await.is_some() { + if tree.update(cx, |tree, _| tree.entry_for_path(file_name).is_none()) { + break; + } + } cx.update(|cx| tree.read(cx).as_local().unwrap().scan_complete()) .await; @@ -5958,19 +5964,22 @@ impl WorktreeModelHandle for Entity { .await .unwrap(); - cx.condition(&tree, |tree, _| { - scan_id_increased(tree, &mut git_dir_scan_id) - }) - .await; + let mut events = cx.events(&tree); + while events.next().await.is_some() { + if tree.update(cx, |tree, _| scan_id_increased(tree, &mut git_dir_scan_id)) { + break; + } + } fs.remove_file(&root_path.join(file_name), Default::default()) .await .unwrap(); - cx.condition(&tree, |tree, _| { - scan_id_increased(tree, &mut git_dir_scan_id) - }) - .await; + while events.next().await.is_some() { + if tree.update(cx, |tree, _| scan_id_increased(tree, &mut git_dir_scan_id)) { + break; + } + } cx.update(|cx| tree.read(cx).as_local().unwrap().scan_complete()) .await; diff --git a/crates/worktree/src/worktree_tests.rs b/crates/worktree/src/worktree_tests.rs index 15131b0eac17624414f00ee26f50e343412b782b..616213020d7e88b3fc01fcfa797fd352a4d82c19 100644 --- a/crates/worktree/src/worktree_tests.rs +++ b/crates/worktree/src/worktree_tests.rs @@ -12,6 +12,7 @@ use git::{ }, GITIGNORE, }; +use git2::RepositoryInitOptions; use gpui::{AppContext as _, BorrowAppContext, Context, Task, TestAppContext}; use parking_lot::Mutex; use postage::stream::Stream; @@ -855,7 +856,7 @@ async fn test_write_file(cx: &mut TestAppContext) { "ignored-dir": {} })); - let tree = Worktree::local( + let worktree = Worktree::local( dir.path(), true, Arc::new(RealFs::default()), @@ -868,32 +869,34 @@ async fn test_write_file(cx: &mut TestAppContext) { #[cfg(not(target_os = "macos"))] fs::fs_watcher::global(|_| {}).unwrap(); - cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) + cx.read(|cx| worktree.read(cx).as_local().unwrap().scan_complete()) .await; - tree.flush_fs_events(cx).await; + worktree.flush_fs_events(cx).await; - tree.update(cx, |tree, cx| { - tree.write_file( - Path::new("tracked-dir/file.txt"), - "hello".into(), - Default::default(), - cx, - ) - }) - .await - .unwrap(); - tree.update(cx, |tree, cx| { - tree.write_file( - Path::new("ignored-dir/file.txt"), - "world".into(), - Default::default(), - cx, - ) - }) - .await - .unwrap(); + worktree + .update(cx, |tree, cx| { + tree.write_file( + Path::new("tracked-dir/file.txt"), + "hello".into(), + Default::default(), + cx, + ) + }) + .await + .unwrap(); + worktree + .update(cx, |tree, cx| { + tree.write_file( + Path::new("ignored-dir/file.txt"), + "world".into(), + Default::default(), + cx, + ) + }) + .await + .unwrap(); - tree.read_with(cx, |tree, _| { + worktree.read_with(cx, |tree, _| { let tracked = tree.entry_for_path("tracked-dir/file.txt").unwrap(); let ignored = tree.entry_for_path("ignored-dir/file.txt").unwrap(); assert!(!tracked.is_ignored); @@ -3349,7 +3352,7 @@ async fn test_conflicted_cherry_pick(cx: &mut TestAppContext) { .expect("Failed to get HEAD") .peel_to_commit() .expect("HEAD is not a commit"); - git_checkout("refs/heads/master", &repo); + git_checkout("refs/heads/main", &repo); std::fs::write(root_path.join("project/a.txt"), "b").unwrap(); git_add("a.txt", &repo); git_commit("improve letter", &repo); @@ -3479,7 +3482,9 @@ const MODIFIED: GitSummary = GitSummary { #[track_caller] fn git_init(path: &Path) -> git2::Repository { - git2::Repository::init(path).expect("Failed to initialize git repository") + let mut init_opts = RepositoryInitOptions::new(); + init_opts.initial_head("main"); + git2::Repository::init_opts(path, &init_opts).expect("Failed to initialize git repository") } #[track_caller]