Git on main thread (#26573)

This moves spawning of the git subprocess to the main thread. We're not
yet
sure why, but when we spawn a process using GCD's background queues,
sub-processes like git-credential-manager fail to open windows.

This seems to be fixable either by using the main thread, or by using a
standard background thread,
but for now we use the main thread.


Release Notes:

- Git: Fix git-credential-manager

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
Conrad Irwin 2025-03-12 13:39:30 -06:00 committed by GitHub
parent 5268e74315
commit 7bca15704b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 926 additions and 713 deletions

View file

@ -6770,7 +6770,7 @@ async fn test_remote_git_branches(
assert_eq!(branches_b, branches_set);
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch))
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch.to_string()))
.await
.unwrap()
.unwrap();
@ -6790,15 +6790,23 @@ async fn test_remote_git_branches(
assert_eq!(host_branch.name, branches[2]);
// Also try creating a new branch
cx_b.update(|cx| repo_b.read(cx).create_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.create_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx_b.update(|cx| repo_b.read(cx).change_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.change_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
executor.run_until_parked();

View file

@ -294,7 +294,7 @@ async fn test_ssh_collaboration_git_branches(
assert_eq!(&branches_b, &branches_set);
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch))
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch.to_string()))
.await
.unwrap()
.unwrap();
@ -316,15 +316,23 @@ async fn test_ssh_collaboration_git_branches(
assert_eq!(server_branch.name, branches[2]);
// Also try creating a new branch
cx_b.update(|cx| repo_b.read(cx).create_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.create_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx_b.update(|cx| repo_b.read(cx).change_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.change_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
executor.run_until_parked();

View file

@ -2,8 +2,8 @@ use crate::commit::get_messages;
use crate::Oid;
use anyhow::{anyhow, Context as _, Result};
use collections::{HashMap, HashSet};
use futures::AsyncWriteExt;
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::process::Stdio;
use std::{ops::Range, path::Path};
use text::Rope;
@ -21,14 +21,14 @@ pub struct Blame {
}
impl Blame {
pub fn for_path(
pub async fn for_path(
git_binary: &Path,
working_directory: &Path,
path: &Path,
content: &Rope,
remote_url: Option<String>,
) -> Result<Self> {
let output = run_git_blame(git_binary, working_directory, path, content)?;
let output = run_git_blame(git_binary, working_directory, path, content).await?;
let mut entries = parse_git_blame(&output)?;
entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start));
@ -39,8 +39,9 @@ impl Blame {
}
let shas = unique_shas.into_iter().collect::<Vec<_>>();
let messages =
get_messages(working_directory, &shas).context("failed to get commit messages")?;
let messages = get_messages(working_directory, &shas)
.await
.context("failed to get commit messages")?;
Ok(Self {
entries,
@ -53,13 +54,13 @@ impl Blame {
const GIT_BLAME_NO_COMMIT_ERROR: &str = "fatal: no such ref: HEAD";
const GIT_BLAME_NO_PATH: &str = "fatal: no such path";
fn run_git_blame(
async fn run_git_blame(
git_binary: &Path,
working_directory: &Path,
path: &Path,
contents: &Rope,
) -> Result<String> {
let child = util::command::new_std_command(git_binary)
let mut child = util::command::new_smol_command(git_binary)
.current_dir(working_directory)
.arg("blame")
.arg("--incremental")
@ -72,18 +73,19 @@ fn run_git_blame(
.spawn()
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
let mut stdin = child
let stdin = child
.stdin
.as_ref()
.as_mut()
.context("failed to get pipe to stdin of git blame command")?;
for chunk in contents.chunks() {
stdin.write_all(chunk.as_bytes())?;
stdin.write_all(chunk.as_bytes()).await?;
}
stdin.flush()?;
stdin.flush().await?;
let output = child
.wait_with_output()
.output()
.await
.map_err(|e| anyhow!("Failed to read git blame output: {}", e))?;
if !output.status.success() {

View file

@ -3,20 +3,21 @@ use anyhow::{anyhow, Result};
use collections::HashMap;
use std::path::Path;
pub fn get_messages(working_directory: &Path, 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());
}
const MARKER: &str = "<MARKER>";
let output = util::command::new_std_command("git")
let output = util::command::new_smol_command("git")
.current_dir(working_directory)
.arg("show")
.arg("-s")
.arg(format!("--format=%B{}", MARKER))
.args(shas.iter().map(ToString::to_string))
.output()
.await
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
anyhow::ensure!(

File diff suppressed because it is too large Load diff

View file

@ -205,9 +205,9 @@ impl BranchListDelegate {
return;
};
cx.spawn(|_, cx| async move {
cx.update(|cx| repo.read(cx).create_branch(&new_branch_name))?
cx.update(|cx| repo.read(cx).create_branch(new_branch_name.to_string()))?
.await??;
cx.update(|cx| repo.read(cx).change_branch(&new_branch_name))?
cx.update(|cx| repo.read(cx).change_branch(new_branch_name.to_string()))?
.await??;
Ok(())
})
@ -358,7 +358,7 @@ impl PickerDelegate for BranchListDelegate {
let cx = cx.to_async();
anyhow::Ok(async move {
cx.update(|cx| repo.read(cx).change_branch(&branch.name))?
cx.update(|cx| repo.read(cx).change_branch(branch.name.to_string()))?
.await?
})
})??;

View file

@ -1501,15 +1501,17 @@ impl GitPanel {
telemetry::event!("Git Uncommitted");
let confirmation = self.check_for_pushed_commits(window, cx);
let prior_head = self.load_commit_details("HEAD", cx);
let prior_head = self.load_commit_details("HEAD".to_string(), cx);
let task = cx.spawn_in(window, |this, mut cx| async move {
let result = maybe!(async {
if let Ok(true) = confirmation.await {
let prior_head = prior_head.await?;
repo.update(&mut cx, |repo, cx| repo.reset("HEAD^", ResetMode::Soft, cx))?
.await??;
repo.update(&mut cx, |repo, cx| {
repo.reset("HEAD^".to_string(), ResetMode::Soft, cx)
})?
.await??;
Ok(Some(prior_head))
} else {
@ -3401,7 +3403,7 @@ impl GitPanel {
fn load_commit_details(
&self,
sha: &str,
sha: String,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<CommitDetails>> {
let Some(repo) = self.active_repository.clone() else {
@ -3911,7 +3913,7 @@ impl GitPanelMessageTooltip {
cx.spawn_in(window, |this, mut cx| async move {
let details = git_panel
.update(&mut cx, |git_panel, cx| {
git_panel.load_commit_details(&sha, cx)
git_panel.load_commit_details(sha.to_string(), cx)
})?
.await?;

View file

@ -837,52 +837,63 @@ impl LocalBufferStore {
let snapshot =
worktree_handle.update(&mut cx, |tree, _| tree.as_local().unwrap().snapshot())?;
let diff_bases_changes_by_buffer = cx
.background_spawn(async move {
diff_state_updates
.into_iter()
.filter_map(|(buffer, path, current_index_text, current_head_text)| {
let local_repo = snapshot.local_repo_for_path(&path)?;
let relative_path = local_repo.relativize(&path).ok()?;
let index_text = if current_index_text.is_some() {
local_repo.repo().load_index_text(&relative_path)
} else {
None
};
let head_text = if current_head_text.is_some() {
local_repo.repo().load_committed_text(&relative_path)
} else {
None
};
.spawn(async move |cx| {
let mut results = Vec::new();
for (buffer, path, current_index_text, current_head_text) in diff_state_updates
{
let Some(local_repo) = snapshot.local_repo_for_path(&path) else {
continue;
};
let Some(relative_path) = local_repo.relativize(&path).ok() else {
continue;
};
let index_text = if current_index_text.is_some() {
local_repo
.repo()
.load_index_text(relative_path.clone(), cx.clone())
.await
} else {
None
};
let head_text = if current_head_text.is_some() {
local_repo
.repo()
.load_committed_text(relative_path, cx.clone())
.await
} else {
None
};
// Avoid triggering a diff update if the base text has not changed.
if let Some((current_index, current_head)) =
current_index_text.as_ref().zip(current_head_text.as_ref())
// Avoid triggering a diff update if the base text has not changed.
if let Some((current_index, current_head)) =
current_index_text.as_ref().zip(current_head_text.as_ref())
{
if current_index.as_deref() == index_text.as_ref()
&& current_head.as_deref() == head_text.as_ref()
{
if current_index.as_deref() == index_text.as_ref()
&& current_head.as_deref() == head_text.as_ref()
{
return None;
}
continue;
}
}
let diff_bases_change =
match (current_index_text.is_some(), current_head_text.is_some()) {
(true, true) => Some(if index_text == head_text {
DiffBasesChange::SetBoth(head_text)
} else {
DiffBasesChange::SetEach {
index: index_text,
head: head_text,
}
}),
(true, false) => Some(DiffBasesChange::SetIndex(index_text)),
(false, true) => Some(DiffBasesChange::SetHead(head_text)),
(false, false) => None,
};
let diff_bases_change =
match (current_index_text.is_some(), current_head_text.is_some()) {
(true, true) => Some(if index_text == head_text {
DiffBasesChange::SetBoth(head_text)
} else {
DiffBasesChange::SetEach {
index: index_text,
head: head_text,
}
}),
(true, false) => Some(DiffBasesChange::SetIndex(index_text)),
(false, true) => Some(DiffBasesChange::SetHead(head_text)),
(false, false) => None,
};
Some((buffer, diff_bases_change))
})
.collect::<Vec<_>>()
results.push((buffer, diff_bases_change))
}
results
})
.await;
@ -1620,11 +1631,12 @@ impl BufferStore {
anyhow::Ok(Some((repo, relative_path, content)))
});
cx.background_spawn(async move {
cx.spawn(|cx| async move {
let Some((repo, relative_path, content)) = blame_params? else {
return Ok(None);
};
repo.blame(&relative_path, content)
repo.blame(relative_path.clone(), content, cx)
.await
.with_context(|| format!("Failed to blame {:?}", relative_path.0))
.map(Some)
})

View file

@ -401,7 +401,7 @@ impl GitStore {
if let Some((repo, path)) = this.repository_and_path_for_buffer_id(buffer_id, cx) {
let recv = repo.update(cx, |repo, cx| {
repo.set_index_text(
&path,
path,
new_index_text.as_ref().map(|rope| rope.to_string()),
cx,
)
@ -715,7 +715,7 @@ impl GitStore {
repository_handle
.update(&mut cx, |repository_handle, cx| {
repository_handle.set_index_text(
&RepoPath::from_str(&envelope.payload.path),
RepoPath::from_str(&envelope.payload.path),
envelope.payload.text,
cx,
)
@ -808,7 +808,7 @@ impl GitStore {
repository_handle
.update(&mut cx, |repository_handle, _| {
repository_handle.create_branch(&branch_name)
repository_handle.create_branch(branch_name)
})?
.await??;
@ -828,7 +828,7 @@ impl GitStore {
repository_handle
.update(&mut cx, |repository_handle, _| {
repository_handle.change_branch(&branch_name)
repository_handle.change_branch(branch_name)
})?
.await??;
@ -847,7 +847,7 @@ impl GitStore {
let commit = repository_handle
.update(&mut cx, |repository_handle, _| {
repository_handle.show(&envelope.payload.commit)
repository_handle.show(envelope.payload.commit)
})?
.await??;
Ok(proto::GitCommitDetails {
@ -876,7 +876,7 @@ impl GitStore {
repository_handle
.update(&mut cx, |repository_handle, cx| {
repository_handle.reset(&envelope.payload.commit, mode, cx)
repository_handle.reset(envelope.payload.commit, mode, cx)
})?
.await??;
Ok(proto::Ack {})
@ -1081,8 +1081,8 @@ impl Repository {
fn send_job<F, Fut, R>(&self, job: F) -> oneshot::Receiver<R>
where
F: FnOnce(GitRepo) -> Fut + 'static,
Fut: Future<Output = R> + Send + 'static,
F: FnOnce(GitRepo, AsyncApp) -> Fut + 'static,
Fut: Future<Output = R> + 'static,
R: Send + 'static,
{
self.send_keyed_job(None, job)
@ -1090,8 +1090,8 @@ impl Repository {
fn send_keyed_job<F, Fut, R>(&self, key: Option<GitJobKey>, job: F) -> oneshot::Receiver<R>
where
F: FnOnce(GitRepo) -> Fut + 'static,
Fut: Future<Output = R> + Send + 'static,
F: FnOnce(GitRepo, AsyncApp) -> Fut + 'static,
Fut: Future<Output = R> + 'static,
R: Send + 'static,
{
let (result_tx, result_rx) = futures::channel::oneshot::channel();
@ -1100,8 +1100,8 @@ impl Repository {
.unbounded_send(GitJob {
key,
job: Box::new(|cx: &mut AsyncApp| {
let job = job(git_repo);
cx.background_spawn(async move {
let job = job(git_repo, cx.clone());
cx.spawn(|_| async move {
let result = job.await;
result_tx.send(result).ok();
})
@ -1292,9 +1292,9 @@ impl Repository {
let commit = commit.to_string();
let env = self.worktree_environment(cx);
self.send_job(|git_repo| async move {
self.send_job(|git_repo, _| async move {
match git_repo {
GitRepo::Local(repo) => repo.checkout_files(&commit, &paths, &env.await),
GitRepo::Local(repo) => repo.checkout_files(commit, paths, env.await).await,
GitRepo::Remote {
project_id,
client,
@ -1322,17 +1322,17 @@ impl Repository {
pub fn reset(
&self,
commit: &str,
commit: String,
reset_mode: ResetMode,
cx: &mut App,
) -> oneshot::Receiver<Result<()>> {
let commit = commit.to_string();
let env = self.worktree_environment(cx);
self.send_job(|git_repo| async move {
self.send_job(|git_repo, _| async move {
match git_repo {
GitRepo::Local(git_repo) => {
let env = env.await;
git_repo.reset(&commit, reset_mode, &env)
git_repo.reset(commit, reset_mode, env).await
}
GitRepo::Remote {
project_id,
@ -1359,11 +1359,10 @@ impl Repository {
})
}
pub fn show(&self, commit: &str) -> oneshot::Receiver<Result<CommitDetails>> {
let commit = commit.to_string();
self.send_job(|git_repo| async move {
pub fn show(&self, commit: String) -> oneshot::Receiver<Result<CommitDetails>> {
self.send_job(|git_repo, cx| async move {
match git_repo {
GitRepo::Local(git_repository) => git_repository.show(&commit),
GitRepo::Local(git_repository) => git_repository.show(commit, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1433,9 +1432,9 @@ impl Repository {
let env = env.await;
this.update(&mut cx, |this, _| {
this.send_job(|git_repo| async move {
this.send_job(|git_repo, cx| async move {
match git_repo {
GitRepo::Local(repo) => repo.stage_paths(&entries, &env),
GitRepo::Local(repo) => repo.stage_paths(entries, env, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1504,9 +1503,9 @@ impl Repository {
let env = env.await;
this.update(&mut cx, |this, _| {
this.send_job(|git_repo| async move {
this.send_job(|git_repo, cx| async move {
match git_repo {
GitRepo::Local(repo) => repo.unstage_paths(&entries, &env),
GitRepo::Local(repo) => repo.unstage_paths(entries, env, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1587,17 +1586,11 @@ impl Repository {
cx: &mut App,
) -> oneshot::Receiver<Result<()>> {
let env = self.worktree_environment(cx);
self.send_job(|git_repo| async move {
self.send_job(|git_repo, cx| async move {
match git_repo {
GitRepo::Local(repo) => {
let env = env.await;
repo.commit(
message.as_ref(),
name_and_email
.as_ref()
.map(|(name, email)| (name.as_ref(), email.as_ref())),
&env,
)
repo.commit(message, name_and_email, env, cx).await
}
GitRepo::Remote {
project_id,
@ -1634,12 +1627,12 @@ impl Repository {
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
let env = self.worktree_environment(cx);
self.send_job(move |git_repo| async move {
self.send_job(move |git_repo, cx| async move {
match git_repo {
GitRepo::Local(git_repository) => {
let askpass = AskPassSession::new(&executor, askpass).await?;
let env = env.await;
git_repository.fetch(askpass, &env)
git_repository.fetch(askpass, env, cx).await
}
GitRepo::Remote {
project_id,
@ -1685,12 +1678,21 @@ impl Repository {
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
let env = self.worktree_environment(cx);
self.send_job(move |git_repo| async move {
self.send_job(move |git_repo, cx| async move {
match git_repo {
GitRepo::Local(git_repository) => {
let env = env.await;
let askpass = AskPassSession::new(&executor, askpass).await?;
git_repository.push(&branch, &remote, options, askpass, &env)
git_repository
.push(
branch.to_string(),
remote.to_string(),
options,
askpass,
env,
cx,
)
.await
}
GitRepo::Remote {
project_id,
@ -1740,12 +1742,14 @@ impl Repository {
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
let env = self.worktree_environment(cx);
self.send_job(move |git_repo| async move {
self.send_job(move |git_repo, cx| async move {
match git_repo {
GitRepo::Local(git_repository) => {
let askpass = AskPassSession::new(&executor, askpass).await?;
let env = env.await;
git_repository.pull(&branch, &remote, askpass, &env)
git_repository
.pull(branch.to_string(), remote.to_string(), askpass, env, cx)
.await
}
GitRepo::Remote {
project_id,
@ -1781,18 +1785,17 @@ impl Repository {
fn set_index_text(
&self,
path: &RepoPath,
path: RepoPath,
content: Option<String>,
cx: &mut App,
) -> oneshot::Receiver<anyhow::Result<()>> {
let path = path.clone();
let env = self.worktree_environment(cx);
self.send_keyed_job(
Some(GitJobKey::WriteIndex(path.clone())),
|git_repo| async move {
|git_repo, cx| async move {
match git_repo {
GitRepo::Local(repo) => repo.set_index_text(&path, content, &env.await),
GitRepo::Local(repo) => repo.set_index_text(path, content, env.await, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1819,11 +1822,9 @@ impl Repository {
&self,
branch_name: Option<String>,
) -> oneshot::Receiver<Result<Vec<Remote>>> {
self.send_job(|repo| async move {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => {
git_repository.get_remotes(branch_name.as_deref())
}
GitRepo::Local(git_repository) => git_repository.get_remotes(branch_name, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1854,9 +1855,13 @@ impl Repository {
}
pub fn branches(&self) -> oneshot::Receiver<Result<Vec<Branch>>> {
self.send_job(|repo| async move {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => git_repository.branches(),
GitRepo::Local(git_repository) => {
let git_repository = git_repository.clone();
cx.background_spawn(async move { git_repository.branches().await })
.await
}
GitRepo::Remote {
project_id,
client,
@ -1884,9 +1889,9 @@ impl Repository {
}
pub fn diff(&self, diff_type: DiffType, _cx: &App) -> oneshot::Receiver<Result<String>> {
self.send_job(|repo| async move {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => git_repository.diff(diff_type),
GitRepo::Local(git_repository) => git_repository.diff(diff_type, cx).await,
GitRepo::Remote {
project_id,
client,
@ -1916,11 +1921,12 @@ impl Repository {
})
}
pub fn create_branch(&self, branch_name: &str) -> oneshot::Receiver<Result<()>> {
let branch_name = branch_name.to_owned();
self.send_job(|repo| async move {
pub fn create_branch(&self, branch_name: String) -> oneshot::Receiver<Result<()>> {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => git_repository.create_branch(&branch_name),
GitRepo::Local(git_repository) => {
git_repository.create_branch(branch_name, cx).await
}
GitRepo::Remote {
project_id,
client,
@ -1942,11 +1948,12 @@ impl Repository {
})
}
pub fn change_branch(&self, branch_name: &str) -> oneshot::Receiver<Result<()>> {
let branch_name = branch_name.to_owned();
self.send_job(|repo| async move {
pub fn change_branch(&self, branch_name: String) -> oneshot::Receiver<Result<()>> {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => git_repository.change_branch(&branch_name),
GitRepo::Local(git_repository) => {
git_repository.change_branch(branch_name, cx).await
}
GitRepo::Remote {
project_id,
client,
@ -1969,9 +1976,9 @@ impl Repository {
}
pub fn check_for_pushed_commits(&self) -> oneshot::Receiver<Result<Vec<SharedString>>> {
self.send_job(|repo| async move {
self.send_job(|repo, cx| async move {
match repo {
GitRepo::Local(git_repository) => git_repository.check_for_pushed_commit(),
GitRepo::Local(git_repository) => git_repository.check_for_pushed_commit(cx).await,
GitRepo::Remote {
project_id,
client,

View file

@ -1361,7 +1361,7 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
assert_eq!(&remote_branches, &branches_set);
cx.update(|cx| repository.read(cx).change_branch(new_branch))
cx.update(|cx| repository.read(cx).change_branch(new_branch.to_string()))
.await
.unwrap()
.unwrap();
@ -1383,15 +1383,23 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
assert_eq!(server_branch.name, branches[2]);
// Also try creating a new branch
cx.update(|cx| repository.read(cx).create_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx.update(|cx| {
repository
.read(cx)
.create_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx.update(|cx| repository.read(cx).change_branch("totally-new-branch"))
.await
.unwrap()
.unwrap();
cx.update(|cx| {
repository
.read(cx)
.change_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx.run_until_parked();

View file

@ -1055,13 +1055,13 @@ impl Worktree {
Worktree::Local(this) => {
let path = Arc::from(path);
let snapshot = this.snapshot();
cx.background_spawn(async move {
cx.spawn(|cx| async move {
if let Some(repo) = snapshot.repository_for_path(&path) {
if let Some(repo_path) = repo.relativize(&path).log_err() {
if let Some(git_repo) =
snapshot.git_repositories.get(&repo.work_directory_id)
{
return Ok(git_repo.repo_ptr.load_index_text(&repo_path));
return Ok(git_repo.repo_ptr.load_index_text(repo_path, cx).await);
}
}
}
@ -1079,13 +1079,16 @@ impl Worktree {
Worktree::Local(this) => {
let path = Arc::from(path);
let snapshot = this.snapshot();
cx.background_spawn(async move {
cx.spawn(|cx| async move {
if let Some(repo) = snapshot.repository_for_path(&path) {
if let Some(repo_path) = repo.relativize(&path).log_err() {
if let Some(git_repo) =
snapshot.git_repositories.get(&repo.work_directory_id)
{
return Ok(git_repo.repo_ptr.load_committed_text(&repo_path));
return Ok(git_repo
.repo_ptr
.load_committed_text(repo_path, cx)
.await);
}
}
}
@ -5520,7 +5523,9 @@ impl BackgroundScanner {
state.repository_scans.insert(
path_key.clone(),
self.executor.spawn(async move {
update_branches(&job_state, &mut local_repository).log_err();
update_branches(&job_state, &mut local_repository)
.await
.log_err();
log::trace!("updating git statuses for repo {repository_name}",);
let t0 = Instant::now();
@ -5665,11 +5670,11 @@ fn send_status_update_inner(
.is_ok()
}
fn update_branches(
async fn update_branches(
state: &Mutex<BackgroundScannerState>,
repository: &mut LocalRepositoryEntry,
) -> Result<()> {
let branches = repository.repo().branches()?;
let branches = repository.repo().branches().await?;
let snapshot = state.lock().snapshot.snapshot.clone();
let mut repository = snapshot
.repository(repository.work_directory.path_key())