Revert "git: Add trusted worktree support to git integrations (#50649)"

Anthony Eid created

This reverts commit 50c4005eaa5f618683555982cc164e02750a296d.

Will cherry pick to stable in a couple of days.

Change summary

crates/fs/src/fake_git_repo.rs  |  12 
crates/fs/src/fs.rs             |   1 
crates/git/clippy.toml          |  28 --
crates/git/src/blame.rs         |  24 +
crates/git/src/commit.rs        |  17 
crates/git/src/repository.rs    | 475 +++++++++++++++++++++-------------
crates/project/src/git_store.rs |  61 ----
7 files changed, 319 insertions(+), 299 deletions(-)

Detailed changes

crates/fs/src/fake_git_repo.rs 🔗

@@ -20,7 +20,7 @@ use ignore::gitignore::GitignoreBuilder;
 use parking_lot::Mutex;
 use rope::Rope;
 use smol::{channel::Sender, future::FutureExt as _};
-use std::{path::PathBuf, sync::Arc, sync::atomic::AtomicBool};
+use std::{path::PathBuf, sync::Arc};
 use text::LineEnding;
 use util::{paths::PathStyle, rel_path::RelPath};
 
@@ -32,7 +32,6 @@ pub struct FakeGitRepository {
     pub(crate) dot_git_path: PathBuf,
     pub(crate) repository_dir_path: PathBuf,
     pub(crate) common_dir_path: PathBuf,
-    pub(crate) is_trusted: Arc<AtomicBool>,
 }
 
 #[derive(Debug, Clone)]
@@ -882,15 +881,6 @@ impl GitRepository for FakeGitRepository {
     fn commit_data_reader(&self) -> Result<CommitDataReader> {
         anyhow::bail!("commit_data_reader not supported for FakeGitRepository")
     }
-
-    fn set_trusted(&self, trusted: bool) {
-        self.is_trusted
-            .store(trusted, std::sync::atomic::Ordering::Release);
-    }
-
-    fn is_trusted(&self) -> bool {
-        self.is_trusted.load(std::sync::atomic::Ordering::Acquire)
-    }
 }
 
 #[cfg(test)]

crates/fs/src/fs.rs 🔗

@@ -2776,7 +2776,6 @@ impl Fs for FakeFs {
                     repository_dir_path: repository_dir_path.to_owned(),
                     common_dir_path: common_dir_path.to_owned(),
                     checkpoints: Arc::default(),
-                    is_trusted: Arc::default(),
                 }) as _
             },
         )

crates/git/clippy.toml 🔗

@@ -1,28 +0,0 @@
-allow-private-module-inception = true
-avoid-breaking-exported-api = false
-ignore-interior-mutability = [
-    # Suppresses clippy::mutable_key_type, which is a false positive as the Eq
-    # and Hash impls do not use fields with interior mutability.
-    "agent_ui::context::AgentContextKey"
-]
-disallowed-methods = [
-    { path = "std::process::Command::spawn", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::spawn" },
-    { path = "std::process::Command::output", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::output" },
-    { path = "std::process::Command::status", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::status" },
-    { path = "std::process::Command::stdin", reason = "`smol::process::Command::from()` does not preserve stdio configuration", replacement = "smol::process::Command::stdin" },
-    { path = "std::process::Command::stdout", reason = "`smol::process::Command::from()` does not preserve stdio configuration", replacement = "smol::process::Command::stdout" },
-    { path = "std::process::Command::stderr", reason = "`smol::process::Command::from()` does not preserve stdio configuration", replacement = "smol::process::Command::stderr" },
-    { path = "smol::Timer::after", reason = "smol::Timer introduces non-determinism in tests", replacement = "gpui::BackgroundExecutor::timer" },
-    { path = "serde_json::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892. Use `serde_json::from_slice` instead." },
-    { path = "serde_json_lenient::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892, Use `serde_json_lenient::from_slice` instead." },
-    { path = "cocoa::foundation::NSString::alloc", reason = "NSString must be autoreleased to avoid memory leaks. Use `ns_string()` helper instead." },
-    { path = "smol::process::Command::new", reason = "Git commands must go through `GitBinary::build_command` to ensure security flags like `-c core.fsmonitor=false` are always applied.", replacement = "GitBinary::build_command" },
-    { path = "util::command::new_command", reason = "Git commands must go through `GitBinary::build_command` to ensure security flags like `-c core.fsmonitor=false` are always applied.", replacement = "GitBinary::build_command" },
-    { path = "util::command::Command::new", reason = "Git commands must go through `GitBinary::build_command` to ensure security flags like `-c core.fsmonitor=false` are always applied.", replacement = "GitBinary::build_command" },
-]
-disallowed-types = [
-    # { path = "std::collections::HashMap", replacement = "collections::HashMap" },
-    # { path = "std::collections::HashSet", replacement = "collections::HashSet" },
-    # { path = "indexmap::IndexSet", replacement = "collections::IndexSet" },
-    # { path = "indexmap::IndexMap", replacement = "collections::IndexMap" },
-]

crates/git/src/blame.rs 🔗

@@ -1,11 +1,11 @@
 use crate::Oid;
 use crate::commit::get_messages;
-use crate::repository::{GitBinary, RepoPath};
+use crate::repository::RepoPath;
 use anyhow::{Context as _, Result};
 use collections::{HashMap, HashSet};
 use futures::AsyncWriteExt;
 use serde::{Deserialize, Serialize};
-use std::ops::Range;
+use std::{ops::Range, path::Path};
 use text::{LineEnding, Rope};
 use time::OffsetDateTime;
 use time::UtcOffset;
@@ -21,13 +21,15 @@ pub struct Blame {
 }
 
 impl Blame {
-    pub(crate) async fn for_path(
-        git: &GitBinary,
+    pub async fn for_path(
+        git_binary: &Path,
+        working_directory: &Path,
         path: &RepoPath,
         content: &Rope,
         line_ending: LineEnding,
     ) -> Result<Self> {
-        let output = run_git_blame(git, path, content, line_ending).await?;
+        let output =
+            run_git_blame(git_binary, working_directory, path, content, line_ending).await?;
         let mut entries = parse_git_blame(&output)?;
         entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start));
 
@@ -38,7 +40,7 @@ impl Blame {
         }
 
         let shas = unique_shas.into_iter().collect::<Vec<_>>();
-        let messages = get_messages(git, &shas)
+        let messages = get_messages(working_directory, &shas)
             .await
             .context("failed to get commit messages")?;
 
@@ -50,7 +52,8 @@ const GIT_BLAME_NO_COMMIT_ERROR: &str = "fatal: no such ref: HEAD";
 const GIT_BLAME_NO_PATH: &str = "fatal: no such path";
 
 async fn run_git_blame(
-    git: &GitBinary,
+    git_binary: &Path,
+    working_directory: &Path,
     path: &RepoPath,
     contents: &Rope,
     line_ending: LineEnding,
@@ -58,7 +61,12 @@ async fn run_git_blame(
     let mut child = {
         let span = ztracing::debug_span!("spawning git-blame command", path = path.as_unix_str());
         let _enter = span.enter();
-        git.build_command(["blame", "--incremental", "--contents", "-"])
+        util::command::new_command(git_binary)
+            .current_dir(working_directory)
+            .arg("blame")
+            .arg("--incremental")
+            .arg("--contents")
+            .arg("-")
             .arg(path.as_unix_str())
             .stdin(Stdio::piped())
             .stdout(Stdio::piped())

crates/git/src/commit.rs 🔗

@@ -1,11 +1,11 @@
 use crate::{
     BuildCommitPermalinkParams, GitHostingProviderRegistry, GitRemote, Oid, parse_git_remote_url,
-    repository::GitBinary, status::StatusCode,
+    status::StatusCode,
 };
 use anyhow::{Context as _, Result};
 use collections::HashMap;
 use gpui::SharedString;
-use std::sync::Arc;
+use std::{path::Path, sync::Arc};
 
 #[derive(Clone, Debug, Default)]
 pub struct ParsedCommitMessage {
@@ -48,7 +48,7 @@ impl ParsedCommitMessage {
     }
 }
 
-pub(crate) async fn get_messages(git: &GitBinary, shas: &[Oid]) -> Result<HashMap<Oid, String>> {
+pub async fn get_messages(working_directory: &Path, shas: &[Oid]) -> Result<HashMap<Oid, String>> {
     if shas.is_empty() {
         return Ok(HashMap::default());
     }
@@ -63,12 +63,12 @@ pub(crate) async fn get_messages(git: &GitBinary, shas: &[Oid]) -> Result<HashMa
 
         let mut result = vec![];
         for shas in shas.chunks(MAX_ENTRIES_PER_INVOCATION) {
-            let partial = get_messages_impl(git, shas).await?;
+            let partial = get_messages_impl(working_directory, shas).await?;
             result.extend(partial);
         }
         result
     } else {
-        get_messages_impl(git, shas).await?
+        get_messages_impl(working_directory, shas).await?
     };
 
     Ok(shas
@@ -78,10 +78,11 @@ pub(crate) async fn get_messages(git: &GitBinary, shas: &[Oid]) -> Result<HashMa
         .collect::<HashMap<Oid, String>>())
 }
 
-async fn get_messages_impl(git: &GitBinary, shas: &[Oid]) -> Result<Vec<String>> {
+async fn get_messages_impl(working_directory: &Path, shas: &[Oid]) -> Result<Vec<String>> {
     const MARKER: &str = "<MARKER>";
-    let output = git
-        .build_command(["show"])
+    let output = util::command::new_command("git")
+        .current_dir(working_directory)
+        .arg("show")
         .arg("-s")
         .arg(format!("--format=%B{}", MARKER))
         .args(shas.iter().map(ToString::to_string))

crates/git/src/repository.rs 🔗

@@ -21,7 +21,6 @@ use text::LineEnding;
 
 use std::collections::HashSet;
 use std::ffi::{OsStr, OsString};
-use std::sync::atomic::AtomicBool;
 
 use std::process::ExitStatus;
 use std::str::FromStr;
@@ -934,9 +933,6 @@ pub trait GitRepository: Send + Sync {
     ) -> BoxFuture<'_, Result<()>>;
 
     fn commit_data_reader(&self) -> Result<CommitDataReader>;
-
-    fn set_trusted(&self, trusted: bool);
-    fn is_trusted(&self) -> bool;
 }
 
 pub enum DiffType {
@@ -963,7 +959,6 @@ pub struct RealGitRepository {
     pub any_git_binary_path: PathBuf,
     any_git_binary_help_output: Arc<Mutex<Option<SharedString>>>,
     executor: BackgroundExecutor,
-    is_trusted: Arc<AtomicBool>,
 }
 
 impl RealGitRepository {
@@ -982,7 +977,6 @@ impl RealGitRepository {
             any_git_binary_path,
             executor,
             any_git_binary_help_output: Arc::new(Mutex::new(None)),
-            is_trusted: Arc::new(AtomicBool::new(false)),
         })
     }
 
@@ -994,24 +988,20 @@ impl RealGitRepository {
             .map(Path::to_path_buf)
     }
 
-    fn git_binary(&self) -> Result<GitBinary> {
-        Ok(GitBinary::new(
-            self.any_git_binary_path.clone(),
-            self.working_directory()
-                .with_context(|| "Can't run git commands without a working directory")?,
-            self.executor.clone(),
-            self.is_trusted(),
-        ))
-    }
-
     async fn any_git_binary_help_output(&self) -> SharedString {
         if let Some(output) = self.any_git_binary_help_output.lock().clone() {
             return output;
         }
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let executor = self.executor.clone();
+        let working_directory = self.working_directory();
         let output: SharedString = self
             .executor
-            .spawn(async move { git_binary?.run(["help", "-a"]).await })
+            .spawn(async move {
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(["help", "-a"])
+                    .await
+            })
             .await
             .unwrap_or_default()
             .into();
@@ -1054,7 +1044,6 @@ pub async fn get_git_committer(cx: &AsyncApp) -> GitCommitter {
         git_binary_path.unwrap_or(PathBuf::from("git")),
         paths::home_dir().clone(),
         cx.background_executor().clone(),
-        true,
     );
 
     cx.background_spawn(async move {
@@ -1086,12 +1075,14 @@ impl GitRepository for RealGitRepository {
     }
 
     fn show(&self, commit: String) -> BoxFuture<'_, Result<CommitDetails>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command([
+                let working_directory = working_directory?;
+                let output = new_command(git_binary_path)
+                    .current_dir(&working_directory)
+                    .args([
                         "--no-optional-locks",
                         "show",
                         "--no-patch",
@@ -1122,14 +1113,15 @@ impl GitRepository for RealGitRepository {
     }
 
     fn load_commit(&self, commit: String, cx: AsyncApp) -> BoxFuture<'_, Result<CommitDiff>> {
-        if self.repository.lock().workdir().is_none() {
+        let Some(working_directory) = self.repository.lock().workdir().map(ToOwned::to_owned)
+        else {
             return future::ready(Err(anyhow!("no working directory"))).boxed();
-        }
-        let git_binary = self.git_binary();
+        };
+        let git_binary_path = self.any_git_binary_path.clone();
         cx.background_spawn(async move {
-            let git = git_binary?;
-            let show_output = git
-                .build_command([
+            let show_output = util::command::new_command(&git_binary_path)
+                .current_dir(&working_directory)
+                .args([
                     "--no-optional-locks",
                     "show",
                     "--format=",
@@ -1150,8 +1142,9 @@ impl GitRepository for RealGitRepository {
             let changes = parse_git_diff_name_status(&show_stdout);
             let parent_sha = format!("{}^", commit);
 
-            let mut cat_file_process = git
-                .build_command(["--no-optional-locks", "cat-file", "--batch=%(objectsize)"])
+            let mut cat_file_process = util::command::new_command(&git_binary_path)
+                .current_dir(&working_directory)
+                .args(["--no-optional-locks", "cat-file", "--batch=%(objectsize)"])
                 .stdin(Stdio::piped())
                 .stdout(Stdio::piped())
                 .stderr(Stdio::piped())
@@ -1258,17 +1251,18 @@ impl GitRepository for RealGitRepository {
         mode: ResetMode,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
         async move {
+            let working_directory = self.working_directory();
+
             let mode_flag = match mode {
                 ResetMode::Mixed => "--mixed",
                 ResetMode::Soft => "--soft",
             };
 
-            let git = git_binary?;
-            let output = git
-                .build_command(["reset", mode_flag, &commit])
+            let output = new_command(&self.any_git_binary_path)
                 .envs(env.iter())
+                .current_dir(&working_directory?)
+                .args(["reset", mode_flag, &commit])
                 .output()
                 .await?;
             anyhow::ensure!(
@@ -1287,16 +1281,17 @@ impl GitRepository for RealGitRepository {
         paths: Vec<RepoPath>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         async move {
             if paths.is_empty() {
                 return Ok(());
             }
 
-            let git = git_binary?;
-            let output = git
-                .build_command(["checkout", &commit, "--"])
+            let output = new_command(&git_binary_path)
+                .current_dir(&working_directory?)
                 .envs(env.iter())
+                .args(["checkout", &commit, "--"])
                 .args(paths.iter().map(|path| path.as_unix_str()))
                 .output()
                 .await?;
@@ -1383,16 +1378,18 @@ impl GitRepository for RealGitRepository {
         env: Arc<HashMap<String, String>>,
         is_executable: bool,
     ) -> BoxFuture<'_, anyhow::Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
                 let mode = if is_executable { "100755" } else { "100644" };
 
                 if let Some(content) = content {
-                    let mut child = git
-                        .build_command(["hash-object", "-w", "--stdin"])
+                    let mut child = new_command(&git_binary_path)
+                        .current_dir(&working_directory)
                         .envs(env.iter())
+                        .args(["hash-object", "-w", "--stdin"])
                         .stdin(Stdio::piped())
                         .stdout(Stdio::piped())
                         .spawn()?;
@@ -1405,9 +1402,10 @@ impl GitRepository for RealGitRepository {
 
                     log::debug!("indexing SHA: {sha}, path {path:?}");
 
-                    let output = git
-                        .build_command(["update-index", "--add", "--cacheinfo", mode, sha])
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory)
                         .envs(env.iter())
+                        .args(["update-index", "--add", "--cacheinfo", mode, sha])
                         .arg(path.as_unix_str())
                         .output()
                         .await?;
@@ -1419,9 +1417,10 @@ impl GitRepository for RealGitRepository {
                     );
                 } else {
                     log::debug!("removing path {path:?} from the index");
-                    let output = git
-                        .build_command(["update-index", "--force-remove"])
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory)
                         .envs(env.iter())
+                        .args(["update-index", "--force-remove"])
                         .arg(path.as_unix_str())
                         .output()
                         .await?;
@@ -1450,12 +1449,14 @@ impl GitRepository for RealGitRepository {
     }
 
     fn revparse_batch(&self, revs: Vec<String>) -> BoxFuture<'_, Result<Vec<Option<String>>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let mut process = git
-                    .build_command([
+                let working_directory = working_directory?;
+                let mut process = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args([
                         "--no-optional-locks",
                         "cat-file",
                         "--batch-check=%(objectname)",
@@ -1508,14 +1509,19 @@ impl GitRepository for RealGitRepository {
     }
 
     fn status(&self, path_prefixes: &[RepoPath]) -> Task<Result<GitStatus>> {
-        let git = match self.git_binary() {
-            Ok(git) => git,
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = match self.working_directory() {
+            Ok(working_directory) => working_directory,
             Err(e) => return Task::ready(Err(e)),
         };
         let args = git_status_args(path_prefixes);
         log::debug!("Checking for git status in {path_prefixes:?}");
         self.executor.spawn(async move {
-            let output = git.build_command(args).output().await?;
+            let output = new_command(&git_binary_path)
+                .current_dir(working_directory)
+                .args(args)
+                .output()
+                .await?;
             if output.status.success() {
                 let stdout = String::from_utf8_lossy(&output.stdout);
                 stdout.parse()
@@ -1527,8 +1533,9 @@ impl GitRepository for RealGitRepository {
     }
 
     fn diff_tree(&self, request: DiffTreeType) -> BoxFuture<'_, Result<TreeDiff>> {
-        let git = match self.git_binary() {
-            Ok(git) => git,
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = match self.working_directory() {
+            Ok(working_directory) => working_directory,
             Err(e) => return Task::ready(Err(e)).boxed(),
         };
 
@@ -1553,7 +1560,11 @@ impl GitRepository for RealGitRepository {
 
         self.executor
             .spawn(async move {
-                let output = git.build_command(args).output().await?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(working_directory)
+                    .args(args)
+                    .output()
+                    .await?;
                 if output.status.success() {
                     let stdout = String::from_utf8_lossy(&output.stdout);
                     stdout.parse()
@@ -1566,12 +1577,13 @@ impl GitRepository for RealGitRepository {
     }
 
     fn stash_entries(&self) -> BoxFuture<'_, Result<GitStash>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command(&["stash", "list", "--pretty=format:%gd%x00%H%x00%ct%x00%s"])
+                let output = new_command(&git_binary_path)
+                    .current_dir(working_directory?)
+                    .args(&["stash", "list", "--pretty=format:%gd%x00%H%x00%ct%x00%s"])
                     .output()
                     .await?;
                 if output.status.success() {
@@ -1586,7 +1598,8 @@ impl GitRepository for RealGitRepository {
     }
 
     fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
                 let fields = [
@@ -1608,8 +1621,12 @@ impl GitRepository for RealGitRepository {
                     "--format",
                     &fields,
                 ];
-                let git = git_binary?;
-                let output = git.build_command(args).output().await?;
+                let working_directory = working_directory?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args(args)
+                    .output()
+                    .await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -1623,7 +1640,11 @@ impl GitRepository for RealGitRepository {
                 if branches.is_empty() {
                     let args = vec!["symbolic-ref", "--quiet", "HEAD"];
 
-                    let output = git.build_command(args).output().await?;
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory)
+                        .args(args)
+                        .output()
+                        .await?;
 
                     // git symbolic-ref returns a non-0 exit code if HEAD points
                     // to something other than a branch
@@ -1645,12 +1666,13 @@ impl GitRepository for RealGitRepository {
     }
 
     fn worktrees(&self) -> BoxFuture<'_, Result<Vec<Worktree>>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command(&["--no-optional-locks", "worktree", "list", "--porcelain"])
+                let output = new_command(&git_binary_path)
+                    .current_dir(working_directory?)
+                    .args(&["--no-optional-locks", "worktree", "list", "--porcelain"])
                     .output()
                     .await?;
                 if output.status.success() {
@@ -1670,7 +1692,8 @@ impl GitRepository for RealGitRepository {
         directory: PathBuf,
         from_commit: Option<String>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
         let final_path = directory.join(&name);
         let mut args = vec![
             OsString::from("--no-optional-locks"),
@@ -1690,8 +1713,11 @@ impl GitRepository for RealGitRepository {
         self.executor
             .spawn(async move {
                 std::fs::create_dir_all(final_path.parent().unwrap_or(&final_path))?;
-                let git = git_binary?;
-                let output = git.build_command(args).output().await?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(working_directory?)
+                    .args(args)
+                    .output()
+                    .await?;
                 if output.status.success() {
                     Ok(())
                 } else {
@@ -1703,7 +1729,9 @@ impl GitRepository for RealGitRepository {
     }
 
     fn remove_worktree(&self, path: PathBuf, force: bool) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
+        let executor = self.executor.clone();
 
         self.executor
             .spawn(async move {
@@ -1717,14 +1745,18 @@ impl GitRepository for RealGitRepository {
                 }
                 args.push("--".into());
                 args.push(path.as_os_str().into());
-                git_binary?.run(args).await?;
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(args)
+                    .await?;
                 anyhow::Ok(())
             })
             .boxed()
     }
 
     fn rename_worktree(&self, old_path: PathBuf, new_path: PathBuf) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
+        let executor = self.executor.clone();
 
         self.executor
             .spawn(async move {
@@ -1736,7 +1768,9 @@ impl GitRepository for RealGitRepository {
                     old_path.as_os_str().into(),
                     new_path.as_os_str().into(),
                 ];
-                git_binary?.run(args).await?;
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(args)
+                    .await?;
                 anyhow::Ok(())
             })
             .boxed()
@@ -1744,7 +1778,9 @@ impl GitRepository for RealGitRepository {
 
     fn change_branch(&self, name: String) -> BoxFuture<'_, Result<()>> {
         let repo = self.repository.clone();
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let executor = self.executor.clone();
         let branch = self.executor.spawn(async move {
             let repo = repo.lock();
             let branch = if let Ok(branch) = repo.find_branch(&name, BranchType::Local) {
@@ -1779,7 +1815,9 @@ impl GitRepository for RealGitRepository {
         self.executor
             .spawn(async move {
                 let branch = branch.await?;
-                git_binary?.run(&["checkout", &branch]).await?;
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(&["checkout", &branch])
+                    .await?;
                 anyhow::Ok(())
             })
             .boxed()
@@ -1790,7 +1828,9 @@ impl GitRepository for RealGitRepository {
         name: String,
         base_branch: Option<String>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
+        let executor = self.executor.clone();
 
         self.executor
             .spawn(async move {
@@ -1801,18 +1841,22 @@ impl GitRepository for RealGitRepository {
                     args.push(&base_branch_str);
                 }
 
-                git_binary?.run(&args).await?;
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(&args)
+                    .await?;
                 anyhow::Ok(())
             })
             .boxed()
     }
 
     fn rename_branch(&self, branch: String, new_name: String) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
+        let executor = self.executor.clone();
 
         self.executor
             .spawn(async move {
-                git_binary?
+                GitBinary::new(git_binary_path, working_directory?, executor)
                     .run(&["branch", "-m", &branch, &new_name])
                     .await?;
                 anyhow::Ok(())
@@ -1821,11 +1865,15 @@ impl GitRepository for RealGitRepository {
     }
 
     fn delete_branch(&self, name: String) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let working_directory = self.working_directory();
+        let executor = self.executor.clone();
 
         self.executor
             .spawn(async move {
-                git_binary?.run(&["branch", "-d", &name]).await?;
+                GitBinary::new(git_binary_path, working_directory?, executor)
+                    .run(&["branch", "-d", &name])
+                    .await?;
                 anyhow::Ok(())
             })
             .boxed()
@@ -1837,11 +1885,20 @@ impl GitRepository for RealGitRepository {
         content: Rope,
         line_ending: LineEnding,
     ) -> BoxFuture<'_, Result<crate::blame::Blame>> {
-        let git = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let executor = self.executor.clone();
 
-        self.executor
+        executor
             .spawn(async move {
-                crate::blame::Blame::for_path(&git?, &path, &content, line_ending).await
+                crate::blame::Blame::for_path(
+                    &git_binary_path,
+                    &working_directory?,
+                    &path,
+                    &content,
+                    line_ending,
+                )
+                .await
             })
             .boxed()
     }
@@ -1856,10 +1913,11 @@ impl GitRepository for RealGitRepository {
         skip: usize,
         limit: Option<usize>,
     ) -> BoxFuture<'_, Result<FileHistory>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
                 // Use a unique delimiter with a hardcoded UUID to separate commits
                 // This essentially eliminates any chance of encountering the delimiter in actual commit data
                 let commit_delimiter =
@@ -1887,8 +1945,9 @@ impl GitRepository for RealGitRepository {
 
                 args.push("--");
 
-                let output = git
-                    .build_command(&args)
+                let output = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args(&args)
                     .arg(path.as_unix_str())
                     .output()
                     .await?;
@@ -1933,17 +1992,30 @@ impl GitRepository for RealGitRepository {
     }
 
     fn diff(&self, diff: DiffType) -> BoxFuture<'_, Result<String>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
                 let output = match diff {
                     DiffType::HeadToIndex => {
-                        git.build_command(["diff", "--staged"]).output().await?
+                        new_command(&git_binary_path)
+                            .current_dir(&working_directory)
+                            .args(["diff", "--staged"])
+                            .output()
+                            .await?
+                    }
+                    DiffType::HeadToWorktree => {
+                        new_command(&git_binary_path)
+                            .current_dir(&working_directory)
+                            .args(["diff"])
+                            .output()
+                            .await?
                     }
-                    DiffType::HeadToWorktree => git.build_command(["diff"]).output().await?,
                     DiffType::MergeBase { base_ref } => {
-                        git.build_command(["diff", "--merge-base", base_ref.as_ref()])
+                        new_command(&git_binary_path)
+                            .current_dir(&working_directory)
+                            .args(["diff", "--merge-base", base_ref.as_ref()])
                             .output()
                             .await?
                     }
@@ -1964,14 +2036,15 @@ impl GitRepository for RealGitRepository {
         paths: Vec<RepoPath>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
                 if !paths.is_empty() {
-                    let git = git_binary?;
-                    let output = git
-                        .build_command(["update-index", "--add", "--remove", "--"])
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory?)
                         .envs(env.iter())
+                        .args(["update-index", "--add", "--remove", "--"])
                         .args(paths.iter().map(|p| p.as_unix_str()))
                         .output()
                         .await?;
@@ -1991,15 +2064,16 @@ impl GitRepository for RealGitRepository {
         paths: Vec<RepoPath>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
 
         self.executor
             .spawn(async move {
                 if !paths.is_empty() {
-                    let git = git_binary?;
-                    let output = git
-                        .build_command(["reset", "--quiet", "--"])
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory?)
                         .envs(env.iter())
+                        .args(["reset", "--quiet", "--"])
                         .args(paths.iter().map(|p| p.as_std_path()))
                         .output()
                         .await?;
@@ -2020,16 +2094,19 @@ impl GitRepository for RealGitRepository {
         paths: Vec<RepoPath>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command(["stash", "push", "--quiet", "--include-untracked"])
+                let mut cmd = new_command(&git_binary_path);
+                cmd.current_dir(&working_directory?)
                     .envs(env.iter())
-                    .args(paths.iter().map(|p| p.as_unix_str()))
-                    .output()
-                    .await?;
+                    .args(["stash", "push", "--quiet"])
+                    .arg("--include-untracked");
+
+                cmd.args(paths.iter().map(|p| p.as_unix_str()));
+
+                let output = cmd.output().await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -2046,15 +2123,20 @@ impl GitRepository for RealGitRepository {
         index: Option<usize>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let mut cmd = new_command(git_binary_path);
                 let mut args = vec!["stash".to_string(), "pop".to_string()];
                 if let Some(index) = index {
                     args.push(format!("stash@{{{}}}", index));
                 }
-                let output = git.build_command(&args).envs(env.iter()).output().await?;
+                cmd.current_dir(&working_directory?)
+                    .envs(env.iter())
+                    .args(args);
+
+                let output = cmd.output().await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -2071,15 +2153,20 @@ impl GitRepository for RealGitRepository {
         index: Option<usize>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let mut cmd = new_command(git_binary_path);
                 let mut args = vec!["stash".to_string(), "apply".to_string()];
                 if let Some(index) = index {
                     args.push(format!("stash@{{{}}}", index));
                 }
-                let output = git.build_command(&args).envs(env.iter()).output().await?;
+                cmd.current_dir(&working_directory?)
+                    .envs(env.iter())
+                    .args(args);
+
+                let output = cmd.output().await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -2096,15 +2183,20 @@ impl GitRepository for RealGitRepository {
         index: Option<usize>,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let mut cmd = new_command(git_binary_path);
                 let mut args = vec!["stash".to_string(), "drop".to_string()];
                 if let Some(index) = index {
                     args.push(format!("stash@{{{}}}", index));
                 }
-                let output = git.build_command(&args).envs(env.iter()).output().await?;
+                cmd.current_dir(&working_directory?)
+                    .envs(env.iter())
+                    .args(args);
+
+                let output = cmd.output().await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -2124,14 +2216,16 @@ impl GitRepository for RealGitRepository {
         ask_pass: AskPassDelegate,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         let executor = self.executor.clone();
         // Note: Do not spawn this command on the background thread, it might pop open the credential helper
         // which we want to block on.
         async move {
-            let git = git_binary?;
-            let mut cmd = git.build_command(["commit", "--quiet", "-m"]);
-            cmd.envs(env.iter())
+            let mut cmd = new_command(git_binary_path);
+            cmd.current_dir(&working_directory?)
+                .envs(env.iter())
+                .args(["commit", "--quiet", "-m"])
                 .arg(&message.to_string())
                 .arg("--cleanup=strip")
                 .arg("--no-verify")
@@ -2170,21 +2264,16 @@ impl GitRepository for RealGitRepository {
         let working_directory = self.working_directory();
         let executor = cx.background_executor().clone();
         let git_binary_path = self.system_git_binary_path.clone();
-        let is_trusted = self.is_trusted();
         // Note: Do not spawn this command on the background thread, it might pop open the credential helper
         // which we want to block on.
         async move {
             let git_binary_path = git_binary_path.context("git not found on $PATH, can't push")?;
             let working_directory = working_directory?;
-            let git = GitBinary::new(
-                git_binary_path,
-                working_directory,
-                executor.clone(),
-                is_trusted,
-            );
-            let mut command = git.build_command(["push"]);
+            let mut command = new_command(git_binary_path);
             command
                 .envs(env.iter())
+                .current_dir(&working_directory)
+                .args(["push"])
                 .args(options.map(|option| match option {
                     PushOptions::SetUpstream => "--set-upstream",
                     PushOptions::Force => "--force-with-lease",
@@ -2212,20 +2301,15 @@ impl GitRepository for RealGitRepository {
         let working_directory = self.working_directory();
         let executor = cx.background_executor().clone();
         let git_binary_path = self.system_git_binary_path.clone();
-        let is_trusted = self.is_trusted();
         // Note: Do not spawn this command on the background thread, it might pop open the credential helper
         // which we want to block on.
         async move {
             let git_binary_path = git_binary_path.context("git not found on $PATH, can't pull")?;
-            let working_directory = working_directory?;
-            let git = GitBinary::new(
-                git_binary_path,
-                working_directory,
-                executor.clone(),
-                is_trusted,
-            );
-            let mut command = git.build_command(["pull"]);
-            command.envs(env.iter());
+            let mut command = new_command(git_binary_path);
+            command
+                .envs(env.iter())
+                .current_dir(&working_directory?)
+                .arg("pull");
 
             if rebase {
                 command.arg("--rebase");
@@ -2253,21 +2337,15 @@ impl GitRepository for RealGitRepository {
         let remote_name = format!("{}", fetch_options);
         let git_binary_path = self.system_git_binary_path.clone();
         let executor = cx.background_executor().clone();
-        let is_trusted = self.is_trusted();
         // Note: Do not spawn this command on the background thread, it might pop open the credential helper
         // which we want to block on.
         async move {
             let git_binary_path = git_binary_path.context("git not found on $PATH, can't fetch")?;
-            let working_directory = working_directory?;
-            let git = GitBinary::new(
-                git_binary_path,
-                working_directory,
-                executor.clone(),
-                is_trusted,
-            );
-            let mut command = git.build_command(["fetch", &remote_name]);
+            let mut command = new_command(git_binary_path);
             command
                 .envs(env.iter())
+                .current_dir(&working_directory?)
+                .args(["fetch", &remote_name])
                 .stdout(Stdio::piped())
                 .stderr(Stdio::piped());
 
@@ -2277,12 +2355,14 @@ impl GitRepository for RealGitRepository {
     }
 
     fn get_push_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command(["rev-parse", "--abbrev-ref"])
+                let working_directory = working_directory?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args(["rev-parse", "--abbrev-ref"])
                     .arg(format!("{branch}@{{push}}"))
                     .output()
                     .await?;
@@ -2302,12 +2382,14 @@ impl GitRepository for RealGitRepository {
     }
 
     fn get_branch_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git
-                    .build_command(["config", "--get"])
+                let working_directory = working_directory?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args(["config", "--get"])
                     .arg(format!("branch.{branch}.remote"))
                     .output()
                     .await?;
@@ -2324,11 +2406,16 @@ impl GitRepository for RealGitRepository {
     }
 
     fn get_all_remotes(&self) -> BoxFuture<'_, Result<Vec<Remote>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
-                let output = git.build_command(["remote", "-v"]).output().await?;
+                let working_directory = working_directory?;
+                let output = new_command(&git_binary_path)
+                    .current_dir(&working_directory)
+                    .args(["remote", "-v"])
+                    .output()
+                    .await?;
 
                 anyhow::ensure!(
                     output.status.success(),
@@ -2377,12 +2464,17 @@ impl GitRepository for RealGitRepository {
     }
 
     fn check_for_pushed_commit(&self) -> BoxFuture<'_, Result<Vec<SharedString>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
                 let git_cmd = async |args: &[&str]| -> Result<String> {
-                    let output = git.build_command(args).output().await?;
+                    let output = new_command(&git_binary_path)
+                        .current_dir(&working_directory)
+                        .args(args)
+                        .output()
+                        .await?;
                     anyhow::ensure!(
                         output.status.success(),
                         String::from_utf8_lossy(&output.stderr).to_string()
@@ -2431,10 +2523,14 @@ impl GitRepository for RealGitRepository {
     }
 
     fn checkpoint(&self) -> BoxFuture<'static, Result<GitRepositoryCheckpoint>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let executor = self.executor.clone();
         self.executor
             .spawn(async move {
-                let mut git = git_binary?.envs(checkpoint_author_envs());
+                let working_directory = working_directory?;
+                let mut git = GitBinary::new(git_binary_path, working_directory.clone(), executor)
+                    .envs(checkpoint_author_envs());
                 git.with_temp_index(async |git| {
                     let head_sha = git.run(&["rev-parse", "HEAD"]).await.ok();
                     let mut excludes = exclude_files(git).await?;
@@ -2460,10 +2556,15 @@ impl GitRepository for RealGitRepository {
     }
 
     fn restore_checkpoint(&self, checkpoint: GitRepositoryCheckpoint) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+
+        let executor = self.executor.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
+
+                let git = GitBinary::new(git_binary_path, working_directory, executor);
                 git.run(&[
                     "restore",
                     "--source",
@@ -2494,10 +2595,14 @@ impl GitRepository for RealGitRepository {
         left: GitRepositoryCheckpoint,
         right: GitRepositoryCheckpoint,
     ) -> BoxFuture<'_, Result<bool>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+
+        let executor = self.executor.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
+                let git = GitBinary::new(git_binary_path, working_directory, executor);
                 let result = git
                     .run(&[
                         "diff-tree",
@@ -2528,10 +2633,14 @@ impl GitRepository for RealGitRepository {
         base_checkpoint: GitRepositoryCheckpoint,
         target_checkpoint: GitRepositoryCheckpoint,
     ) -> BoxFuture<'_, Result<String>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+
+        let executor = self.executor.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
+                let git = GitBinary::new(git_binary_path, working_directory, executor);
                 git.run(&[
                     "diff",
                     "--find-renames",
@@ -2548,10 +2657,14 @@ impl GitRepository for RealGitRepository {
         &self,
         include_remote_name: bool,
     ) -> BoxFuture<'_, Result<Option<SharedString>>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
+        let git_binary_path = self.any_git_binary_path.clone();
+
+        let executor = self.executor.clone();
         self.executor
             .spawn(async move {
-                let git = git_binary?;
+                let working_directory = working_directory?;
+                let git = GitBinary::new(git_binary_path, working_directory, executor);
 
                 let strip_prefix = if include_remote_name {
                     "refs/remotes/"
@@ -2601,19 +2714,15 @@ impl GitRepository for RealGitRepository {
         hook: RunHook,
         env: Arc<HashMap<String, String>>,
     ) -> BoxFuture<'_, Result<()>> {
-        let git_binary = self.git_binary();
+        let working_directory = self.working_directory();
         let repository = self.repository.clone();
+        let git_binary_path = self.any_git_binary_path.clone();
+        let executor = self.executor.clone();
         let help_output = self.any_git_binary_help_output();
 
         // Note: Do not spawn these commands on the background thread, as this causes some git hooks to hang.
         async move {
-            let git = git_binary?;
-
-            if !git.is_trusted {
-                bail!("Can't run git commit hooks in restrictive workspace");
-            }
-
-            let working_directory = git.working_directory.clone();
+            let working_directory = working_directory?;
             if !help_output
                 .await
                 .lines()

crates/project/src/git_store.rs 🔗

@@ -6,9 +6,6 @@ pub mod pending_op;
 use crate::{
     ProjectEnvironment, ProjectItem, ProjectPath,
     buffer_store::{BufferStore, BufferStoreEvent},
-    trusted_worktrees::{
-        PathTrust, TrustedWorktrees, TrustedWorktreesEvent, TrustedWorktreesStore,
-    },
     worktree_store::{WorktreeStore, WorktreeStoreEvent},
 };
 use anyhow::{Context as _, Result, anyhow, bail};
@@ -346,7 +343,6 @@ impl LocalRepositoryState {
         dot_git_abs_path: Arc<Path>,
         project_environment: WeakEntity<ProjectEnvironment>,
         fs: Arc<dyn Fs>,
-        is_trusted: bool,
         cx: &mut AsyncApp,
     ) -> anyhow::Result<Self> {
         let environment = project_environment
@@ -374,7 +370,6 @@ impl LocalRepositoryState {
                 }
             })
             .await?;
-        backend.set_trusted(is_trusted);
         Ok(LocalRepositoryState {
             backend,
             environment: Arc::new(environment),
@@ -483,15 +478,11 @@ impl GitStore {
         state: GitStoreState,
         cx: &mut Context<Self>,
     ) -> Self {
-        let mut _subscriptions = vec![
+        let _subscriptions = vec![
             cx.subscribe(&worktree_store, Self::on_worktree_store_event),
             cx.subscribe(&buffer_store, Self::on_buffer_store_event),
         ];
 
-        if let Some(trusted_worktrees) = TrustedWorktrees::try_get_global(cx) {
-            _subscriptions.push(cx.subscribe(&trusted_worktrees, Self::on_trusted_worktrees_event));
-        }
-
         GitStore {
             state,
             buffer_store,
@@ -1506,13 +1497,6 @@ impl GitStore {
             } = update
             {
                 let id = RepositoryId(next_repository_id.fetch_add(1, atomic::Ordering::Release));
-                let is_trusted = TrustedWorktrees::try_get_global(cx)
-                    .map(|trusted_worktrees| {
-                        trusted_worktrees.update(cx, |trusted_worktrees, cx| {
-                            trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
-                        })
-                    })
-                    .unwrap_or(false);
                 let git_store = cx.weak_entity();
                 let repo = cx.new(|cx| {
                     let mut repo = Repository::local(
@@ -1521,7 +1505,6 @@ impl GitStore {
                         dot_git_abs_path.clone(),
                         project_environment.downgrade(),
                         fs.clone(),
-                        is_trusted,
                         git_store,
                         cx,
                     );
@@ -1562,39 +1545,6 @@ impl GitStore {
         }
     }
 
-    fn on_trusted_worktrees_event(
-        &mut self,
-        _: Entity<TrustedWorktreesStore>,
-        event: &TrustedWorktreesEvent,
-        cx: &mut Context<Self>,
-    ) {
-        if !matches!(self.state, GitStoreState::Local { .. }) {
-            return;
-        }
-
-        let (is_trusted, event_paths) = match event {
-            TrustedWorktreesEvent::Trusted(_, trusted_paths) => (true, trusted_paths),
-            TrustedWorktreesEvent::Restricted(_, restricted_paths) => (false, restricted_paths),
-        };
-
-        for (repo_id, worktree_ids) in &self.worktree_ids {
-            if worktree_ids
-                .iter()
-                .any(|worktree_id| event_paths.contains(&PathTrust::Worktree(*worktree_id)))
-            {
-                if let Some(repo) = self.repositories.get(repo_id) {
-                    let repository_state = repo.read(cx).repository_state.clone();
-                    cx.background_spawn(async move {
-                        if let Ok(RepositoryState::Local(state)) = repository_state.await {
-                            state.backend.set_trusted(is_trusted);
-                        }
-                    })
-                    .detach();
-                }
-            }
-        }
-    }
-
     fn on_buffer_store_event(
         &mut self,
         _: Entity<BufferStore>,
@@ -3743,13 +3693,6 @@ impl MergeDetails {
 }
 
 impl Repository {
-    pub fn is_trusted(&self) -> bool {
-        match self.repository_state.peek() {
-            Some(Ok(RepositoryState::Local(state))) => state.backend.is_trusted(),
-            _ => false,
-        }
-    }
-
     pub fn snapshot(&self) -> RepositorySnapshot {
         self.snapshot.clone()
     }
@@ -3774,7 +3717,6 @@ impl Repository {
         dot_git_abs_path: Arc<Path>,
         project_environment: WeakEntity<ProjectEnvironment>,
         fs: Arc<dyn Fs>,
-        is_trusted: bool,
         git_store: WeakEntity<GitStore>,
         cx: &mut Context<Self>,
     ) -> Self {
@@ -3787,7 +3729,6 @@ impl Repository {
                     dot_git_abs_path,
                     project_environment,
                     fs,
-                    is_trusted,
                     cx,
                 )
                 .await