Detailed changes
@@ -555,6 +555,12 @@
//
// Default: icon
"status_style": "icon",
+ // What branch name to use if init.defaultBranch
+ // is not set
+ //
+ // Default: main
+ "fallback_branch_name": "main",
+
"scrollbar": {
// When to show the scrollbar in the git panel.
//
@@ -396,6 +396,7 @@ impl Server {
.add_request_handler(forward_mutating_project_request::<proto::Stage>)
.add_request_handler(forward_mutating_project_request::<proto::Unstage>)
.add_request_handler(forward_mutating_project_request::<proto::Commit>)
+ .add_request_handler(forward_mutating_project_request::<proto::GitInit>)
.add_request_handler(forward_read_only_project_request::<proto::GetRemotes>)
.add_request_handler(forward_read_only_project_request::<proto::GitShow>)
.add_request_handler(forward_read_only_project_request::<proto::GitReset>)
@@ -16,12 +16,14 @@ use git::{repository::RepoPath, status::FileStatus};
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
use ashpd::desktop::trash;
+use std::borrow::Cow;
#[cfg(any(test, feature = "test-support"))]
use std::collections::HashSet;
#[cfg(unix)]
use std::os::fd::AsFd;
#[cfg(unix)]
use std::os::fd::AsRawFd;
+use util::command::new_std_command;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
@@ -136,6 +138,7 @@ pub trait Fs: Send + Sync {
fn home_dir(&self) -> Option<PathBuf>;
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>>;
+ fn git_init(&self, abs_work_directory: &Path, fallback_branch_name: String) -> Result<()>;
fn is_fake(&self) -> bool;
async fn is_case_sensitive(&self) -> Result<bool>;
@@ -765,6 +768,29 @@ impl Fs for RealFs {
)))
}
+ fn git_init(&self, abs_work_directory_path: &Path, fallback_branch_name: String) -> Result<()> {
+ let config = new_std_command("git")
+ .current_dir(abs_work_directory_path)
+ .args(&["config", "--global", "--get", "init.defaultBranch"])
+ .output()?;
+
+ let branch_name;
+
+ if config.status.success() && !config.stdout.is_empty() {
+ branch_name = String::from_utf8_lossy(&config.stdout);
+ } else {
+ branch_name = Cow::Borrowed(fallback_branch_name.as_str());
+ }
+
+ new_std_command("git")
+ .current_dir(abs_work_directory_path)
+ .args(&["init", "-b"])
+ .arg(branch_name.trim())
+ .output()?;
+
+ Ok(())
+ }
+
fn is_fake(&self) -> bool {
false
}
@@ -2075,6 +2101,14 @@ impl Fs for FakeFs {
}
}
+ fn git_init(
+ &self,
+ abs_work_directory_path: &Path,
+ _fallback_branch_name: String,
+ ) -> Result<()> {
+ smol::block_on(self.create_dir(&abs_work_directory_path.join(".git")))
+ }
+
fn is_fake(&self) -> bool {
true
}
@@ -50,7 +50,8 @@ actions!(
Fetch,
Commit,
ExpandCommitEditor,
- GenerateCommitMessage
+ GenerateCommitMessage,
+ Init,
]
);
action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]);
@@ -1767,6 +1767,88 @@ impl GitPanel {
.detach_and_log_err(cx);
}
+ pub(crate) fn git_init(&mut self, window: &mut Window, cx: &mut Context<Self>) {
+ let worktrees = self
+ .project
+ .read(cx)
+ .visible_worktrees(cx)
+ .collect::<Vec<_>>();
+
+ let worktree = if worktrees.len() == 1 {
+ Task::ready(Some(worktrees.first().unwrap().clone()))
+ } else if worktrees.len() == 0 {
+ let result = window.prompt(
+ PromptLevel::Warning,
+ "Unable to initialize a git repository",
+ Some("Open a directory first"),
+ &["Ok"],
+ cx,
+ );
+ cx.background_executor()
+ .spawn(async move {
+ result.await.ok();
+ })
+ .detach();
+ return;
+ } else {
+ let worktree_directories = worktrees
+ .iter()
+ .map(|worktree| worktree.read(cx).abs_path())
+ .map(|worktree_abs_path| {
+ if let Ok(path) = worktree_abs_path.strip_prefix(util::paths::home_dir()) {
+ Path::new("~")
+ .join(path)
+ .to_string_lossy()
+ .to_string()
+ .into()
+ } else {
+ worktree_abs_path.to_string_lossy().to_string().into()
+ }
+ })
+ .collect_vec();
+ let prompt = picker_prompt::prompt(
+ "Where would you like to initialize this git repository?",
+ worktree_directories,
+ self.workspace.clone(),
+ window,
+ cx,
+ );
+
+ cx.spawn(|_, _| async move { prompt.await.map(|ix| worktrees[ix].clone()) })
+ };
+
+ cx.spawn_in(window, |this, mut cx| async move {
+ let worktree = match worktree.await {
+ Some(worktree) => worktree,
+ None => {
+ return;
+ }
+ };
+
+ let Ok(result) = this.update(&mut cx, |this, cx| {
+ let fallback_branch_name = GitPanelSettings::get_global(cx)
+ .fallback_branch_name
+ .clone();
+ this.project.read(cx).git_init(
+ worktree.read(cx).abs_path(),
+ fallback_branch_name,
+ cx,
+ )
+ }) else {
+ return;
+ };
+
+ let result = result.await;
+
+ this.update_in(&mut cx, |this, _, cx| match result {
+ Ok(()) => {}
+ Err(e) => this.show_error_toast("init", e, cx),
+ })
+ .ok();
+ })
+ .detach();
+ }
+
pub(crate) fn pull(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if !self.can_push_and_pull(cx) {
return;
@@ -1971,7 +2053,7 @@ impl GitPanel {
cx,
)
})?
- .await?;
+ .await;
Ok(selection.map(|selection| Remote {
name: current_remotes[selection].clone(),
@@ -2677,7 +2759,13 @@ impl GitPanel {
})
}
- fn render_panel_header(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ fn render_panel_header(
+ &self,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) -> Option<impl IntoElement> {
+ self.active_repository.as_ref()?;
+
let text;
let action;
let tooltip;
@@ -2697,39 +2785,42 @@ impl GitPanel {
_ => format!("{} Changes", self.entry_count),
};
- self.panel_header_container(window, cx)
- .px_2()
- .child(
- panel_button(change_string)
- .color(Color::Muted)
- .tooltip(Tooltip::for_action_title_in(
- "Open diff",
- &Diff,
- &self.focus_handle,
- ))
- .on_click(|_, _, cx| {
- cx.defer(|cx| {
- cx.dispatch_action(&Diff);
- })
- }),
- )
- .child(div().flex_grow()) // spacer
- .child(self.render_overflow_menu("overflow_menu"))
- .child(
- panel_filled_button(text)
- .tooltip(Tooltip::for_action_title_in(
- tooltip,
- action.as_ref(),
- &self.focus_handle,
- ))
- .disabled(self.entry_count == 0)
- .on_click(move |_, _, cx| {
- let action = action.boxed_clone();
- cx.defer(move |cx| {
- cx.dispatch_action(action.as_ref());
- })
- }),
- )
+ Some(
+ self.panel_header_container(window, cx)
+ .px_2()
+ .child(
+ panel_button(change_string)
+ .color(Color::Muted)
+ .tooltip(Tooltip::for_action_title_in(
+ "Open diff",
+ &Diff,
+ &self.focus_handle,
+ ))
+ .on_click(|_, _, cx| {
+ cx.defer(|cx| {
+ cx.dispatch_action(&Diff);
+ })
+ }),
+ )
+ .child(div().flex_grow()) // spacer
+ .child(self.render_overflow_menu("overflow_menu"))
+ .child(div().w_2()) // another spacer
+ .child(
+ panel_filled_button(text)
+ .tooltip(Tooltip::for_action_title_in(
+ tooltip,
+ action.as_ref(),
+ &self.focus_handle,
+ ))
+ .disabled(self.entry_count == 0)
+ .on_click(move |_, _, cx| {
+ let action = action.boxed_clone();
+ cx.defer(move |cx| {
+ cx.dispatch_action(action.as_ref());
+ })
+ }),
+ ),
+ )
}
pub fn render_footer(
@@ -2949,12 +3040,29 @@ impl GitPanel {
.items_center()
.child(
v_flex()
- .gap_3()
- .child(if self.active_repository.is_some() {
- "No changes to commit"
- } else {
- "No Git repositories"
- })
+ .gap_2()
+ .child(h_flex().w_full().justify_around().child(
+ if self.active_repository.is_some() {
+ "No changes to commit"
+ } else {
+ "No Git repositories"
+ },
+ ))
+ .children(self.active_repository.is_none().then(|| {
+ h_flex().w_full().justify_around().child(
+ panel_filled_button("Initialize Repository")
+ .tooltip(Tooltip::for_action_title_in(
+ "git init",
+ &git::Init,
+ &self.focus_handle,
+ ))
+ .on_click(move |_, _, cx| {
+ cx.defer(move |cx| {
+ cx.dispatch_action(&git::Init);
+ })
+ }),
+ )
+ }))
.text_ui_sm(cx)
.mx_auto()
.text_color(Color::Placeholder.color(cx)),
@@ -3674,7 +3782,7 @@ impl Render for GitPanel {
.child(
v_flex()
.size_full()
- .child(self.render_panel_header(window, cx))
+ .children(self.render_panel_header(window, cx))
.map(|this| {
if has_entries {
this.child(self.render_entries(has_write_access, window, cx))
@@ -58,15 +58,22 @@ pub struct GitPanelSettingsContent {
///
/// Default: inherits editor scrollbar settings
pub scrollbar: Option<ScrollbarSettings>,
+
+ /// What the default branch name should be when
+ /// `init.defaultBranch` is not set in git
+ ///
+ /// Default: main
+ pub fallback_branch_name: Option<String>,
}
-#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
+#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct GitPanelSettings {
pub button: bool,
pub dock: DockPosition,
pub default_width: Pixels,
pub status_style: StatusStyle,
pub scrollbar: ScrollbarSettings,
+ pub fallback_branch_name: String,
}
impl Settings for GitPanelSettings {
@@ -82,6 +82,14 @@ pub fn init(cx: &mut App) {
panel.unstage_all(action, window, cx);
});
});
+ workspace.register_action(|workspace, _action: &git::Init, window, cx| {
+ let Some(panel) = workspace.panel::<git_panel::GitPanel>(cx) else {
+ return;
+ };
+ panel.update(cx, |panel, cx| {
+ panel.git_init(window, cx);
+ });
+ });
})
.detach();
}
@@ -1,4 +1,3 @@
-use anyhow::{anyhow, Result};
use futures::channel::oneshot;
use fuzzy::{StringMatch, StringMatchCandidate};
@@ -26,9 +25,9 @@ pub fn prompt(
workspace: WeakEntity<Workspace>,
window: &mut Window,
cx: &mut App,
-) -> Task<Result<Option<usize>>> {
+) -> Task<Option<usize>> {
if options.is_empty() {
- return Task::ready(Err(anyhow!("No options")));
+ return Task::ready(None);
}
let prompt = prompt.to_string().into();
@@ -37,15 +36,17 @@ pub fn prompt(
let (tx, rx) = oneshot::channel();
let delegate = PickerPromptDelegate::new(prompt, options, tx, 70);
- workspace.update_in(&mut cx, |workspace, window, cx| {
- workspace.toggle_modal(window, cx, |window, cx| {
- PickerPrompt::new(delegate, 34., window, cx)
+ workspace
+ .update_in(&mut cx, |workspace, window, cx| {
+ workspace.toggle_modal(window, cx, |window, cx| {
+ PickerPrompt::new(delegate, 34., window, cx)
+ })
})
- })?;
+ .ok();
match rx.await {
- Ok(selection) => Some(selection).transpose(),
- Err(_) => anyhow::Ok(None), // User cancelled
+ Ok(selection) => Some(selection),
+ Err(_) => None, // User cancelled
}
})
}
@@ -94,14 +95,14 @@ pub struct PickerPromptDelegate {
all_options: Vec<SharedString>,
selected_index: usize,
max_match_length: usize,
- tx: Option<oneshot::Sender<Result<usize>>>,
+ tx: Option<oneshot::Sender<usize>>,
}
impl PickerPromptDelegate {
pub fn new(
prompt: Arc<str>,
options: Vec<SharedString>,
- tx: oneshot::Sender<Result<usize>>,
+ tx: oneshot::Sender<usize>,
max_chars: usize,
) -> Self {
Self {
@@ -200,7 +201,7 @@ impl PickerDelegate for PickerPromptDelegate {
return;
};
- self.tx.take().map(|tx| tx.send(Ok(option.candidate_id)));
+ self.tx.take().map(|tx| tx.send(option.candidate_id));
cx.emit(DismissEvent);
}
@@ -8,6 +8,7 @@ use askpass::{AskPassDelegate, AskPassSession};
use buffer_diff::BufferDiffEvent;
use client::ProjectId;
use collections::HashMap;
+use fs::Fs;
use futures::{
channel::{mpsc, oneshot},
future::OptionFuture,
@@ -38,21 +39,37 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
+
use text::BufferId;
use util::{debug_panic, maybe, ResultExt};
use worktree::{ProjectEntryId, RepositoryEntry, StatusEntry, WorkDirectory};
pub struct GitStore {
+ state: GitStoreState,
buffer_store: Entity<BufferStore>,
- environment: Option<Entity<ProjectEnvironment>>,
- pub(super) project_id: Option<ProjectId>,
- pub(super) client: AnyProtoClient,
repositories: Vec<Entity<Repository>>,
active_index: Option<usize>,
update_sender: mpsc::UnboundedSender<GitJob>,
_subscriptions: [Subscription; 2],
}
+enum GitStoreState {
+ Local {
+ client: AnyProtoClient,
+ environment: Entity<ProjectEnvironment>,
+ fs: Arc<dyn Fs>,
+ },
+ Ssh {
+ environment: Entity<ProjectEnvironment>,
+ upstream_client: AnyProtoClient,
+ project_id: ProjectId,
+ },
+ Remote {
+ upstream_client: AnyProtoClient,
+ project_id: ProjectId,
+ },
+}
+
pub struct Repository {
commit_message_buffer: Option<Entity<Buffer>>,
git_store: WeakEntity<GitStore>,
@@ -101,12 +118,12 @@ enum GitJobKey {
impl EventEmitter<GitEvent> for GitStore {}
impl GitStore {
- pub fn new(
+ pub fn local(
worktree_store: &Entity<WorktreeStore>,
buffer_store: Entity<BufferStore>,
- environment: Option<Entity<ProjectEnvironment>>,
+ environment: Entity<ProjectEnvironment>,
+ fs: Arc<dyn Fs>,
client: AnyProtoClient,
- project_id: Option<ProjectId>,
cx: &mut Context<'_, Self>,
) -> Self {
let update_sender = Self::spawn_git_worker(cx);
@@ -115,11 +132,73 @@ impl GitStore {
cx.subscribe(&buffer_store, Self::on_buffer_store_event),
];
+ let state = GitStoreState::Local {
+ client,
+ environment,
+ fs,
+ };
+
GitStore {
+ state,
+ buffer_store,
+ repositories: Vec::new(),
+ active_index: None,
+ update_sender,
+ _subscriptions,
+ }
+ }
+
+ pub fn remote(
+ worktree_store: &Entity<WorktreeStore>,
+ buffer_store: Entity<BufferStore>,
+ upstream_client: AnyProtoClient,
+ project_id: ProjectId,
+ cx: &mut Context<'_, Self>,
+ ) -> Self {
+ let update_sender = Self::spawn_git_worker(cx);
+ let _subscriptions = [
+ cx.subscribe(worktree_store, Self::on_worktree_store_event),
+ cx.subscribe(&buffer_store, Self::on_buffer_store_event),
+ ];
+
+ let state = GitStoreState::Remote {
+ upstream_client,
project_id,
- client,
+ };
+
+ GitStore {
+ state,
buffer_store,
+ repositories: Vec::new(),
+ active_index: None,
+ update_sender,
+ _subscriptions,
+ }
+ }
+
+ pub fn ssh(
+ worktree_store: &Entity<WorktreeStore>,
+ buffer_store: Entity<BufferStore>,
+ environment: Entity<ProjectEnvironment>,
+ upstream_client: AnyProtoClient,
+ project_id: ProjectId,
+ cx: &mut Context<'_, Self>,
+ ) -> Self {
+ let update_sender = Self::spawn_git_worker(cx);
+ let _subscriptions = [
+ cx.subscribe(worktree_store, Self::on_worktree_store_event),
+ cx.subscribe(&buffer_store, Self::on_buffer_store_event),
+ ];
+
+ let state = GitStoreState::Ssh {
+ upstream_client,
+ project_id,
environment,
+ };
+
+ GitStore {
+ state,
+ buffer_store,
repositories: Vec::new(),
active_index: None,
update_sender,
@@ -132,6 +211,7 @@ impl GitStore {
client.add_entity_request_handler(Self::handle_get_branches);
client.add_entity_request_handler(Self::handle_change_branch);
client.add_entity_request_handler(Self::handle_create_branch);
+ client.add_entity_request_handler(Self::handle_git_init);
client.add_entity_request_handler(Self::handle_push);
client.add_entity_request_handler(Self::handle_pull);
client.add_entity_request_handler(Self::handle_fetch);
@@ -153,6 +233,34 @@ impl GitStore {
.map(|index| self.repositories[index].clone())
}
+ fn client(&self) -> AnyProtoClient {
+ match &self.state {
+ GitStoreState::Local { client, .. } => client.clone(),
+ GitStoreState::Ssh {
+ upstream_client, ..
+ } => upstream_client.clone(),
+ GitStoreState::Remote {
+ upstream_client, ..
+ } => upstream_client.clone(),
+ }
+ }
+
+ fn project_environment(&self) -> Option<Entity<ProjectEnvironment>> {
+ match &self.state {
+ GitStoreState::Local { environment, .. } => Some(environment.clone()),
+ GitStoreState::Ssh { environment, .. } => Some(environment.clone()),
+ GitStoreState::Remote { .. } => None,
+ }
+ }
+
+ fn project_id(&self) -> Option<ProjectId> {
+ match &self.state {
+ GitStoreState::Local { .. } => None,
+ GitStoreState::Ssh { project_id, .. } => Some(*project_id),
+ GitStoreState::Remote { project_id, .. } => Some(*project_id),
+ }
+ }
+
fn on_worktree_store_event(
&mut self,
worktree_store: Entity<WorktreeStore>,
@@ -162,8 +270,8 @@ impl GitStore {
let mut new_repositories = Vec::new();
let mut new_active_index = None;
let this = cx.weak_entity();
- let client = self.client.clone();
- let project_id = self.project_id;
+ let client = self.client();
+ let project_id = self.project_id();
worktree_store.update(cx, |worktree_store, cx| {
for worktree in worktree_store.worktrees() {
@@ -229,9 +337,9 @@ impl GitStore {
});
existing_handle
} else {
+ let environment = self.project_environment();
cx.new(|_| Repository {
- project_environment: self
- .environment
+ project_environment: environment
.as_ref()
.map(|env| env.downgrade()),
git_store: this.clone(),
@@ -382,6 +490,56 @@ impl GitStore {
job_tx
}
+ pub fn git_init(
+ &self,
+ path: Arc<Path>,
+ fallback_branch_name: String,
+ cx: &App,
+ ) -> Task<Result<()>> {
+ match &self.state {
+ GitStoreState::Local { fs, .. } => {
+ let fs = fs.clone();
+ cx.background_executor()
+ .spawn(async move { fs.git_init(&path, fallback_branch_name) })
+ }
+ GitStoreState::Ssh {
+ upstream_client,
+ project_id,
+ ..
+ }
+ | GitStoreState::Remote {
+ upstream_client,
+ project_id,
+ } => {
+ let client = upstream_client.clone();
+ let project_id = *project_id;
+ cx.background_executor().spawn(async move {
+ client
+ .request(proto::GitInit {
+ project_id: project_id.0,
+ abs_path: path.to_string_lossy().to_string(),
+ fallback_branch_name,
+ })
+ .await?;
+ Ok(())
+ })
+ }
+ }
+ }
+
+ async fn handle_git_init(
+ this: Entity<Self>,
+ envelope: TypedEnvelope<proto::GitInit>,
+ cx: AsyncApp,
+ ) -> Result<proto::Ack> {
+ let path: Arc<Path> = PathBuf::from(envelope.payload.abs_path).into();
+ let name = envelope.payload.fallback_branch_name;
+ cx.update(|cx| this.read(cx).git_init(path, name, cx))?
+ .await?;
+
+ Ok(proto::Ack {})
+ }
+
async fn handle_fetch(
this: Entity<Self>,
envelope: TypedEnvelope<proto::Fetch>,
@@ -889,7 +1047,7 @@ fn make_remote_delegate(
) -> AskPassDelegate {
AskPassDelegate::new(cx, move |prompt, tx, cx| {
this.update(cx, |this, cx| {
- let response = this.client.request(proto::AskPassRequest {
+ let response = this.client().request(proto::AskPassRequest {
project_id,
worktree_id: worktree_id.to_proto(),
work_directory_id: work_directory_id.to_proto(),
@@ -841,12 +841,12 @@ impl Project {
});
let git_store = cx.new(|cx| {
- GitStore::new(
+ GitStore::local(
&worktree_store,
buffer_store.clone(),
- Some(environment.clone()),
+ environment.clone(),
+ fs.clone(),
client.clone().into(),
- None,
cx,
)
});
@@ -970,12 +970,12 @@ impl Project {
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
let git_store = cx.new(|cx| {
- GitStore::new(
+ GitStore::ssh(
&worktree_store,
buffer_store.clone(),
- Some(environment.clone()),
+ environment.clone(),
ssh_proto.clone(),
- Some(ProjectId(SSH_PROJECT_ID)),
+ ProjectId(SSH_PROJECT_ID),
cx,
)
});
@@ -1177,12 +1177,12 @@ impl Project {
})?;
let git_store = cx.new(|cx| {
- GitStore::new(
+ GitStore::remote(
+ // In this remote case we pass None for the environment
&worktree_store,
buffer_store.clone(),
- None,
client.clone().into(),
- Some(ProjectId(remote_id)),
+ ProjectId(remote_id),
cx,
)
})?;
@@ -4443,6 +4443,17 @@ impl Project {
})
}
+ pub fn git_init(
+ &self,
+ path: Arc<Path>,
+ fallback_branch_name: String,
+ cx: &App,
+ ) -> Task<Result<()>> {
+ self.git_store
+ .read(cx)
+ .git_init(path, fallback_branch_name, cx)
+ }
+
pub fn buffer_store(&self) -> &Entity<BufferStore> {
&self.buffer_store
}
@@ -344,7 +344,9 @@ message Envelope {
AskPassResponse ask_pass_response = 318;
GitDiff git_diff = 319;
- GitDiffResponse git_diff_response = 320; // current max
+ GitDiffResponse git_diff_response = 320;
+
+ GitInit git_init = 321; // current max
}
reserved 87 to 88;
@@ -2937,3 +2939,9 @@ message GitDiff {
message GitDiffResponse {
string diff = 1;
}
+
+message GitInit {
+ uint64 project_id = 1;
+ string abs_path = 2;
+ string fallback_branch_name = 3;
+}
@@ -460,6 +460,7 @@ messages!(
(CheckForPushedCommitsResponse, Background),
(GitDiff, Background),
(GitDiffResponse, Background),
+ (GitInit, Background),
);
request_messages!(
@@ -607,6 +608,7 @@ request_messages!(
(GitChangeBranch, Ack),
(CheckForPushedCommits, CheckForPushedCommitsResponse),
(GitDiff, GitDiffResponse),
+ (GitInit, Ack),
);
entity_messages!(
@@ -713,6 +715,7 @@ entity_messages!(
GitCreateBranch,
CheckForPushedCommits,
GitDiff,
+ GitInit,
);
entity_messages!(
@@ -89,12 +89,12 @@ impl HeadlessProject {
let environment = project::ProjectEnvironment::new(&worktree_store, None, cx);
let git_store = cx.new(|cx| {
- GitStore::new(
+ GitStore::local(
&worktree_store,
buffer_store.clone(),
- Some(environment.clone()),
+ environment.clone(),
+ fs.clone(),
session.clone().into(),
- None,
cx,
)
});