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:
parent
5268e74315
commit
7bca15704b
11 changed files with 926 additions and 713 deletions
|
@ -6770,7 +6770,7 @@ async fn test_remote_git_branches(
|
||||||
|
|
||||||
assert_eq!(branches_b, branches_set);
|
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
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -6790,12 +6790,20 @@ async fn test_remote_git_branches(
|
||||||
assert_eq!(host_branch.name, branches[2]);
|
assert_eq!(host_branch.name, branches[2]);
|
||||||
|
|
||||||
// Also try creating a new branch
|
// Also try creating a new branch
|
||||||
cx_b.update(|cx| repo_b.read(cx).create_branch("totally-new-branch"))
|
cx_b.update(|cx| {
|
||||||
|
repo_b
|
||||||
|
.read(cx)
|
||||||
|
.create_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
cx_b.update(|cx| repo_b.read(cx).change_branch("totally-new-branch"))
|
cx_b.update(|cx| {
|
||||||
|
repo_b
|
||||||
|
.read(cx)
|
||||||
|
.change_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -294,7 +294,7 @@ async fn test_ssh_collaboration_git_branches(
|
||||||
|
|
||||||
assert_eq!(&branches_b, &branches_set);
|
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
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -316,12 +316,20 @@ async fn test_ssh_collaboration_git_branches(
|
||||||
assert_eq!(server_branch.name, branches[2]);
|
assert_eq!(server_branch.name, branches[2]);
|
||||||
|
|
||||||
// Also try creating a new branch
|
// Also try creating a new branch
|
||||||
cx_b.update(|cx| repo_b.read(cx).create_branch("totally-new-branch"))
|
cx_b.update(|cx| {
|
||||||
|
repo_b
|
||||||
|
.read(cx)
|
||||||
|
.create_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
cx_b.update(|cx| repo_b.read(cx).change_branch("totally-new-branch"))
|
cx_b.update(|cx| {
|
||||||
|
repo_b
|
||||||
|
.read(cx)
|
||||||
|
.change_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::commit::get_messages;
|
||||||
use crate::Oid;
|
use crate::Oid;
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
|
use futures::AsyncWriteExt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::Write;
|
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::{ops::Range, path::Path};
|
use std::{ops::Range, path::Path};
|
||||||
use text::Rope;
|
use text::Rope;
|
||||||
|
@ -21,14 +21,14 @@ pub struct Blame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Blame {
|
impl Blame {
|
||||||
pub fn for_path(
|
pub async fn for_path(
|
||||||
git_binary: &Path,
|
git_binary: &Path,
|
||||||
working_directory: &Path,
|
working_directory: &Path,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
content: &Rope,
|
content: &Rope,
|
||||||
remote_url: Option<String>,
|
remote_url: Option<String>,
|
||||||
) -> Result<Self> {
|
) -> 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)?;
|
let mut entries = parse_git_blame(&output)?;
|
||||||
entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start));
|
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 shas = unique_shas.into_iter().collect::<Vec<_>>();
|
||||||
let messages =
|
let messages = get_messages(working_directory, &shas)
|
||||||
get_messages(working_directory, &shas).context("failed to get commit messages")?;
|
.await
|
||||||
|
.context("failed to get commit messages")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entries,
|
entries,
|
||||||
|
@ -53,13 +54,13 @@ impl Blame {
|
||||||
const GIT_BLAME_NO_COMMIT_ERROR: &str = "fatal: no such ref: HEAD";
|
const GIT_BLAME_NO_COMMIT_ERROR: &str = "fatal: no such ref: HEAD";
|
||||||
const GIT_BLAME_NO_PATH: &str = "fatal: no such path";
|
const GIT_BLAME_NO_PATH: &str = "fatal: no such path";
|
||||||
|
|
||||||
fn run_git_blame(
|
async fn run_git_blame(
|
||||||
git_binary: &Path,
|
git_binary: &Path,
|
||||||
working_directory: &Path,
|
working_directory: &Path,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
contents: &Rope,
|
contents: &Rope,
|
||||||
) -> Result<String> {
|
) -> 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)
|
.current_dir(working_directory)
|
||||||
.arg("blame")
|
.arg("blame")
|
||||||
.arg("--incremental")
|
.arg("--incremental")
|
||||||
|
@ -72,18 +73,19 @@ fn run_git_blame(
|
||||||
.spawn()
|
.spawn()
|
||||||
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
|
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
|
||||||
|
|
||||||
let mut stdin = child
|
let stdin = child
|
||||||
.stdin
|
.stdin
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.context("failed to get pipe to stdin of git blame command")?;
|
.context("failed to get pipe to stdin of git blame command")?;
|
||||||
|
|
||||||
for chunk in contents.chunks() {
|
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
|
let output = child
|
||||||
.wait_with_output()
|
.output()
|
||||||
|
.await
|
||||||
.map_err(|e| anyhow!("Failed to read git blame output: {}", e))?;
|
.map_err(|e| anyhow!("Failed to read git blame output: {}", e))?;
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
|
|
|
@ -3,20 +3,21 @@ use anyhow::{anyhow, Result};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use std::path::Path;
|
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() {
|
if shas.is_empty() {
|
||||||
return Ok(HashMap::default());
|
return Ok(HashMap::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
const MARKER: &str = "<MARKER>";
|
const MARKER: &str = "<MARKER>";
|
||||||
|
|
||||||
let output = util::command::new_std_command("git")
|
let output = util::command::new_smol_command("git")
|
||||||
.current_dir(working_directory)
|
.current_dir(working_directory)
|
||||||
.arg("show")
|
.arg("show")
|
||||||
.arg("-s")
|
.arg("-s")
|
||||||
.arg(format!("--format=%B{}", MARKER))
|
.arg(format!("--format=%B{}", MARKER))
|
||||||
.args(shas.iter().map(ToString::to_string))
|
.args(shas.iter().map(ToString::to_string))
|
||||||
.output()
|
.output()
|
||||||
|
.await
|
||||||
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
|
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;
|
||||||
|
|
||||||
anyhow::ensure!(
|
anyhow::ensure!(
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -205,9 +205,9 @@ impl BranchListDelegate {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
cx.spawn(|_, cx| async move {
|
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??;
|
.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??;
|
.await??;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -358,7 +358,7 @@ impl PickerDelegate for BranchListDelegate {
|
||||||
let cx = cx.to_async();
|
let cx = cx.to_async();
|
||||||
|
|
||||||
anyhow::Ok(async move {
|
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?
|
.await?
|
||||||
})
|
})
|
||||||
})??;
|
})??;
|
||||||
|
|
|
@ -1501,14 +1501,16 @@ impl GitPanel {
|
||||||
telemetry::event!("Git Uncommitted");
|
telemetry::event!("Git Uncommitted");
|
||||||
|
|
||||||
let confirmation = self.check_for_pushed_commits(window, cx);
|
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 task = cx.spawn_in(window, |this, mut cx| async move {
|
||||||
let result = maybe!(async {
|
let result = maybe!(async {
|
||||||
if let Ok(true) = confirmation.await {
|
if let Ok(true) = confirmation.await {
|
||||||
let prior_head = prior_head.await?;
|
let prior_head = prior_head.await?;
|
||||||
|
|
||||||
repo.update(&mut cx, |repo, cx| repo.reset("HEAD^", ResetMode::Soft, cx))?
|
repo.update(&mut cx, |repo, cx| {
|
||||||
|
repo.reset("HEAD^".to_string(), ResetMode::Soft, cx)
|
||||||
|
})?
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
Ok(Some(prior_head))
|
Ok(Some(prior_head))
|
||||||
|
@ -3401,7 +3403,7 @@ impl GitPanel {
|
||||||
|
|
||||||
fn load_commit_details(
|
fn load_commit_details(
|
||||||
&self,
|
&self,
|
||||||
sha: &str,
|
sha: String,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<anyhow::Result<CommitDetails>> {
|
) -> Task<anyhow::Result<CommitDetails>> {
|
||||||
let Some(repo) = self.active_repository.clone() else {
|
let Some(repo) = self.active_repository.clone() else {
|
||||||
|
@ -3911,7 +3913,7 @@ impl GitPanelMessageTooltip {
|
||||||
cx.spawn_in(window, |this, mut cx| async move {
|
cx.spawn_in(window, |this, mut cx| async move {
|
||||||
let details = git_panel
|
let details = git_panel
|
||||||
.update(&mut cx, |git_panel, cx| {
|
.update(&mut cx, |git_panel, cx| {
|
||||||
git_panel.load_commit_details(&sha, cx)
|
git_panel.load_commit_details(sha.to_string(), cx)
|
||||||
})?
|
})?
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -837,19 +837,29 @@ impl LocalBufferStore {
|
||||||
let snapshot =
|
let snapshot =
|
||||||
worktree_handle.update(&mut cx, |tree, _| tree.as_local().unwrap().snapshot())?;
|
worktree_handle.update(&mut cx, |tree, _| tree.as_local().unwrap().snapshot())?;
|
||||||
let diff_bases_changes_by_buffer = cx
|
let diff_bases_changes_by_buffer = cx
|
||||||
.background_spawn(async move {
|
.spawn(async move |cx| {
|
||||||
diff_state_updates
|
let mut results = Vec::new();
|
||||||
.into_iter()
|
for (buffer, path, current_index_text, current_head_text) in diff_state_updates
|
||||||
.filter_map(|(buffer, path, current_index_text, current_head_text)| {
|
{
|
||||||
let local_repo = snapshot.local_repo_for_path(&path)?;
|
let Some(local_repo) = snapshot.local_repo_for_path(&path) else {
|
||||||
let relative_path = local_repo.relativize(&path).ok()?;
|
continue;
|
||||||
|
};
|
||||||
|
let Some(relative_path) = local_repo.relativize(&path).ok() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let index_text = if current_index_text.is_some() {
|
let index_text = if current_index_text.is_some() {
|
||||||
local_repo.repo().load_index_text(&relative_path)
|
local_repo
|
||||||
|
.repo()
|
||||||
|
.load_index_text(relative_path.clone(), cx.clone())
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let head_text = if current_head_text.is_some() {
|
let head_text = if current_head_text.is_some() {
|
||||||
local_repo.repo().load_committed_text(&relative_path)
|
local_repo
|
||||||
|
.repo()
|
||||||
|
.load_committed_text(relative_path, cx.clone())
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -861,7 +871,7 @@ impl LocalBufferStore {
|
||||||
if current_index.as_deref() == index_text.as_ref()
|
if current_index.as_deref() == index_text.as_ref()
|
||||||
&& current_head.as_deref() == head_text.as_ref()
|
&& current_head.as_deref() == head_text.as_ref()
|
||||||
{
|
{
|
||||||
return None;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,9 +890,10 @@ impl LocalBufferStore {
|
||||||
(false, false) => None,
|
(false, false) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((buffer, diff_bases_change))
|
results.push((buffer, diff_bases_change))
|
||||||
})
|
}
|
||||||
.collect::<Vec<_>>()
|
|
||||||
|
results
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1620,11 +1631,12 @@ impl BufferStore {
|
||||||
anyhow::Ok(Some((repo, relative_path, content)))
|
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 {
|
let Some((repo, relative_path, content)) = blame_params? else {
|
||||||
return Ok(None);
|
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))
|
.with_context(|| format!("Failed to blame {:?}", relative_path.0))
|
||||||
.map(Some)
|
.map(Some)
|
||||||
})
|
})
|
||||||
|
|
|
@ -401,7 +401,7 @@ impl GitStore {
|
||||||
if let Some((repo, path)) = this.repository_and_path_for_buffer_id(buffer_id, cx) {
|
if let Some((repo, path)) = this.repository_and_path_for_buffer_id(buffer_id, cx) {
|
||||||
let recv = repo.update(cx, |repo, cx| {
|
let recv = repo.update(cx, |repo, cx| {
|
||||||
repo.set_index_text(
|
repo.set_index_text(
|
||||||
&path,
|
path,
|
||||||
new_index_text.as_ref().map(|rope| rope.to_string()),
|
new_index_text.as_ref().map(|rope| rope.to_string()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -715,7 +715,7 @@ impl GitStore {
|
||||||
repository_handle
|
repository_handle
|
||||||
.update(&mut cx, |repository_handle, cx| {
|
.update(&mut cx, |repository_handle, cx| {
|
||||||
repository_handle.set_index_text(
|
repository_handle.set_index_text(
|
||||||
&RepoPath::from_str(&envelope.payload.path),
|
RepoPath::from_str(&envelope.payload.path),
|
||||||
envelope.payload.text,
|
envelope.payload.text,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -808,7 +808,7 @@ impl GitStore {
|
||||||
|
|
||||||
repository_handle
|
repository_handle
|
||||||
.update(&mut cx, |repository_handle, _| {
|
.update(&mut cx, |repository_handle, _| {
|
||||||
repository_handle.create_branch(&branch_name)
|
repository_handle.create_branch(branch_name)
|
||||||
})?
|
})?
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -828,7 +828,7 @@ impl GitStore {
|
||||||
|
|
||||||
repository_handle
|
repository_handle
|
||||||
.update(&mut cx, |repository_handle, _| {
|
.update(&mut cx, |repository_handle, _| {
|
||||||
repository_handle.change_branch(&branch_name)
|
repository_handle.change_branch(branch_name)
|
||||||
})?
|
})?
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
@ -847,7 +847,7 @@ impl GitStore {
|
||||||
|
|
||||||
let commit = repository_handle
|
let commit = repository_handle
|
||||||
.update(&mut cx, |repository_handle, _| {
|
.update(&mut cx, |repository_handle, _| {
|
||||||
repository_handle.show(&envelope.payload.commit)
|
repository_handle.show(envelope.payload.commit)
|
||||||
})?
|
})?
|
||||||
.await??;
|
.await??;
|
||||||
Ok(proto::GitCommitDetails {
|
Ok(proto::GitCommitDetails {
|
||||||
|
@ -876,7 +876,7 @@ impl GitStore {
|
||||||
|
|
||||||
repository_handle
|
repository_handle
|
||||||
.update(&mut cx, |repository_handle, cx| {
|
.update(&mut cx, |repository_handle, cx| {
|
||||||
repository_handle.reset(&envelope.payload.commit, mode, cx)
|
repository_handle.reset(envelope.payload.commit, mode, cx)
|
||||||
})?
|
})?
|
||||||
.await??;
|
.await??;
|
||||||
Ok(proto::Ack {})
|
Ok(proto::Ack {})
|
||||||
|
@ -1081,8 +1081,8 @@ impl Repository {
|
||||||
|
|
||||||
fn send_job<F, Fut, R>(&self, job: F) -> oneshot::Receiver<R>
|
fn send_job<F, Fut, R>(&self, job: F) -> oneshot::Receiver<R>
|
||||||
where
|
where
|
||||||
F: FnOnce(GitRepo) -> Fut + 'static,
|
F: FnOnce(GitRepo, AsyncApp) -> Fut + 'static,
|
||||||
Fut: Future<Output = R> + Send + 'static,
|
Fut: Future<Output = R> + 'static,
|
||||||
R: Send + 'static,
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
self.send_keyed_job(None, job)
|
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>
|
fn send_keyed_job<F, Fut, R>(&self, key: Option<GitJobKey>, job: F) -> oneshot::Receiver<R>
|
||||||
where
|
where
|
||||||
F: FnOnce(GitRepo) -> Fut + 'static,
|
F: FnOnce(GitRepo, AsyncApp) -> Fut + 'static,
|
||||||
Fut: Future<Output = R> + Send + 'static,
|
Fut: Future<Output = R> + 'static,
|
||||||
R: Send + 'static,
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
let (result_tx, result_rx) = futures::channel::oneshot::channel();
|
let (result_tx, result_rx) = futures::channel::oneshot::channel();
|
||||||
|
@ -1100,8 +1100,8 @@ impl Repository {
|
||||||
.unbounded_send(GitJob {
|
.unbounded_send(GitJob {
|
||||||
key,
|
key,
|
||||||
job: Box::new(|cx: &mut AsyncApp| {
|
job: Box::new(|cx: &mut AsyncApp| {
|
||||||
let job = job(git_repo);
|
let job = job(git_repo, cx.clone());
|
||||||
cx.background_spawn(async move {
|
cx.spawn(|_| async move {
|
||||||
let result = job.await;
|
let result = job.await;
|
||||||
result_tx.send(result).ok();
|
result_tx.send(result).ok();
|
||||||
})
|
})
|
||||||
|
@ -1292,9 +1292,9 @@ impl Repository {
|
||||||
let commit = commit.to_string();
|
let commit = commit.to_string();
|
||||||
let env = self.worktree_environment(cx);
|
let env = self.worktree_environment(cx);
|
||||||
|
|
||||||
self.send_job(|git_repo| async move {
|
self.send_job(|git_repo, _| async move {
|
||||||
match git_repo {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1322,17 +1322,17 @@ impl Repository {
|
||||||
|
|
||||||
pub fn reset(
|
pub fn reset(
|
||||||
&self,
|
&self,
|
||||||
commit: &str,
|
commit: String,
|
||||||
reset_mode: ResetMode,
|
reset_mode: ResetMode,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> oneshot::Receiver<Result<()>> {
|
) -> oneshot::Receiver<Result<()>> {
|
||||||
let commit = commit.to_string();
|
let commit = commit.to_string();
|
||||||
let env = self.worktree_environment(cx);
|
let env = self.worktree_environment(cx);
|
||||||
self.send_job(|git_repo| async move {
|
self.send_job(|git_repo, _| async move {
|
||||||
match git_repo {
|
match git_repo {
|
||||||
GitRepo::Local(git_repo) => {
|
GitRepo::Local(git_repo) => {
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
git_repo.reset(&commit, reset_mode, &env)
|
git_repo.reset(commit, reset_mode, env).await
|
||||||
}
|
}
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
|
@ -1359,11 +1359,10 @@ impl Repository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show(&self, commit: &str) -> oneshot::Receiver<Result<CommitDetails>> {
|
pub fn show(&self, commit: String) -> oneshot::Receiver<Result<CommitDetails>> {
|
||||||
let commit = commit.to_string();
|
self.send_job(|git_repo, cx| async move {
|
||||||
self.send_job(|git_repo| async move {
|
|
||||||
match git_repo {
|
match git_repo {
|
||||||
GitRepo::Local(git_repository) => git_repository.show(&commit),
|
GitRepo::Local(git_repository) => git_repository.show(commit, cx).await,
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1433,9 +1432,9 @@ impl Repository {
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
|
|
||||||
this.update(&mut cx, |this, _| {
|
this.update(&mut cx, |this, _| {
|
||||||
this.send_job(|git_repo| async move {
|
this.send_job(|git_repo, cx| async move {
|
||||||
match git_repo {
|
match git_repo {
|
||||||
GitRepo::Local(repo) => repo.stage_paths(&entries, &env),
|
GitRepo::Local(repo) => repo.stage_paths(entries, env, cx).await,
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1504,9 +1503,9 @@ impl Repository {
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
|
|
||||||
this.update(&mut cx, |this, _| {
|
this.update(&mut cx, |this, _| {
|
||||||
this.send_job(|git_repo| async move {
|
this.send_job(|git_repo, cx| async move {
|
||||||
match git_repo {
|
match git_repo {
|
||||||
GitRepo::Local(repo) => repo.unstage_paths(&entries, &env),
|
GitRepo::Local(repo) => repo.unstage_paths(entries, env, cx).await,
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1587,17 +1586,11 @@ impl Repository {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> oneshot::Receiver<Result<()>> {
|
) -> oneshot::Receiver<Result<()>> {
|
||||||
let env = self.worktree_environment(cx);
|
let env = self.worktree_environment(cx);
|
||||||
self.send_job(|git_repo| async move {
|
self.send_job(|git_repo, cx| async move {
|
||||||
match git_repo {
|
match git_repo {
|
||||||
GitRepo::Local(repo) => {
|
GitRepo::Local(repo) => {
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
repo.commit(
|
repo.commit(message, name_and_email, env, cx).await
|
||||||
message.as_ref(),
|
|
||||||
name_and_email
|
|
||||||
.as_ref()
|
|
||||||
.map(|(name, email)| (name.as_ref(), email.as_ref())),
|
|
||||||
&env,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
|
@ -1634,12 +1627,12 @@ impl Repository {
|
||||||
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
||||||
let env = self.worktree_environment(cx);
|
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 {
|
match git_repo {
|
||||||
GitRepo::Local(git_repository) => {
|
GitRepo::Local(git_repository) => {
|
||||||
let askpass = AskPassSession::new(&executor, askpass).await?;
|
let askpass = AskPassSession::new(&executor, askpass).await?;
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
git_repository.fetch(askpass, &env)
|
git_repository.fetch(askpass, env, cx).await
|
||||||
}
|
}
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
|
@ -1685,12 +1678,21 @@ impl Repository {
|
||||||
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
||||||
let env = self.worktree_environment(cx);
|
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 {
|
match git_repo {
|
||||||
GitRepo::Local(git_repository) => {
|
GitRepo::Local(git_repository) => {
|
||||||
let env = env.await;
|
let env = env.await;
|
||||||
let askpass = AskPassSession::new(&executor, askpass).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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
|
@ -1740,12 +1742,14 @@ impl Repository {
|
||||||
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
let askpass_id = util::post_inc(&mut self.latest_askpass_id);
|
||||||
let env = self.worktree_environment(cx);
|
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 {
|
match git_repo {
|
||||||
GitRepo::Local(git_repository) => {
|
GitRepo::Local(git_repository) => {
|
||||||
let askpass = AskPassSession::new(&executor, askpass).await?;
|
let askpass = AskPassSession::new(&executor, askpass).await?;
|
||||||
let env = env.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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
|
@ -1781,18 +1785,17 @@ impl Repository {
|
||||||
|
|
||||||
fn set_index_text(
|
fn set_index_text(
|
||||||
&self,
|
&self,
|
||||||
path: &RepoPath,
|
path: RepoPath,
|
||||||
content: Option<String>,
|
content: Option<String>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> oneshot::Receiver<anyhow::Result<()>> {
|
) -> oneshot::Receiver<anyhow::Result<()>> {
|
||||||
let path = path.clone();
|
|
||||||
let env = self.worktree_environment(cx);
|
let env = self.worktree_environment(cx);
|
||||||
|
|
||||||
self.send_keyed_job(
|
self.send_keyed_job(
|
||||||
Some(GitJobKey::WriteIndex(path.clone())),
|
Some(GitJobKey::WriteIndex(path.clone())),
|
||||||
|git_repo| async move {
|
|git_repo, cx| async move {
|
||||||
match git_repo {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1819,11 +1822,9 @@ impl Repository {
|
||||||
&self,
|
&self,
|
||||||
branch_name: Option<String>,
|
branch_name: Option<String>,
|
||||||
) -> oneshot::Receiver<Result<Vec<Remote>>> {
|
) -> oneshot::Receiver<Result<Vec<Remote>>> {
|
||||||
self.send_job(|repo| async move {
|
self.send_job(|repo, cx| async move {
|
||||||
match repo {
|
match repo {
|
||||||
GitRepo::Local(git_repository) => {
|
GitRepo::Local(git_repository) => git_repository.get_remotes(branch_name, cx).await,
|
||||||
git_repository.get_remotes(branch_name.as_deref())
|
|
||||||
}
|
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1854,9 +1855,13 @@ impl Repository {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branches(&self) -> oneshot::Receiver<Result<Vec<Branch>>> {
|
pub fn branches(&self) -> oneshot::Receiver<Result<Vec<Branch>>> {
|
||||||
self.send_job(|repo| async move {
|
self.send_job(|repo, cx| async move {
|
||||||
match repo {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1884,9 +1889,9 @@ impl Repository {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff(&self, diff_type: DiffType, _cx: &App) -> oneshot::Receiver<Result<String>> {
|
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 {
|
match repo {
|
||||||
GitRepo::Local(git_repository) => git_repository.diff(diff_type),
|
GitRepo::Local(git_repository) => git_repository.diff(diff_type, cx).await,
|
||||||
GitRepo::Remote {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1916,11 +1921,12 @@ impl Repository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_branch(&self, branch_name: &str) -> oneshot::Receiver<Result<()>> {
|
pub fn create_branch(&self, branch_name: String) -> oneshot::Receiver<Result<()>> {
|
||||||
let branch_name = branch_name.to_owned();
|
self.send_job(|repo, cx| async move {
|
||||||
self.send_job(|repo| async move {
|
|
||||||
match repo {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1942,11 +1948,12 @@ impl Repository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_branch(&self, branch_name: &str) -> oneshot::Receiver<Result<()>> {
|
pub fn change_branch(&self, branch_name: String) -> oneshot::Receiver<Result<()>> {
|
||||||
let branch_name = branch_name.to_owned();
|
self.send_job(|repo, cx| async move {
|
||||||
self.send_job(|repo| async move {
|
|
||||||
match repo {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
@ -1969,9 +1976,9 @@ impl Repository {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_for_pushed_commits(&self) -> oneshot::Receiver<Result<Vec<SharedString>>> {
|
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 {
|
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 {
|
GitRepo::Remote {
|
||||||
project_id,
|
project_id,
|
||||||
client,
|
client,
|
||||||
|
|
|
@ -1361,7 +1361,7 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
|
||||||
|
|
||||||
assert_eq!(&remote_branches, &branches_set);
|
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
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1383,12 +1383,20 @@ async fn test_remote_git_branches(cx: &mut TestAppContext, server_cx: &mut TestA
|
||||||
assert_eq!(server_branch.name, branches[2]);
|
assert_eq!(server_branch.name, branches[2]);
|
||||||
|
|
||||||
// Also try creating a new branch
|
// Also try creating a new branch
|
||||||
cx.update(|cx| repository.read(cx).create_branch("totally-new-branch"))
|
cx.update(|cx| {
|
||||||
|
repository
|
||||||
|
.read(cx)
|
||||||
|
.create_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
cx.update(|cx| repository.read(cx).change_branch("totally-new-branch"))
|
cx.update(|cx| {
|
||||||
|
repository
|
||||||
|
.read(cx)
|
||||||
|
.change_branch("totally-new-branch".to_string())
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1055,13 +1055,13 @@ impl Worktree {
|
||||||
Worktree::Local(this) => {
|
Worktree::Local(this) => {
|
||||||
let path = Arc::from(path);
|
let path = Arc::from(path);
|
||||||
let snapshot = this.snapshot();
|
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) = snapshot.repository_for_path(&path) {
|
||||||
if let Some(repo_path) = repo.relativize(&path).log_err() {
|
if let Some(repo_path) = repo.relativize(&path).log_err() {
|
||||||
if let Some(git_repo) =
|
if let Some(git_repo) =
|
||||||
snapshot.git_repositories.get(&repo.work_directory_id)
|
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) => {
|
Worktree::Local(this) => {
|
||||||
let path = Arc::from(path);
|
let path = Arc::from(path);
|
||||||
let snapshot = this.snapshot();
|
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) = snapshot.repository_for_path(&path) {
|
||||||
if let Some(repo_path) = repo.relativize(&path).log_err() {
|
if let Some(repo_path) = repo.relativize(&path).log_err() {
|
||||||
if let Some(git_repo) =
|
if let Some(git_repo) =
|
||||||
snapshot.git_repositories.get(&repo.work_directory_id)
|
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(
|
state.repository_scans.insert(
|
||||||
path_key.clone(),
|
path_key.clone(),
|
||||||
self.executor.spawn(async move {
|
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}",);
|
log::trace!("updating git statuses for repo {repository_name}",);
|
||||||
let t0 = Instant::now();
|
let t0 = Instant::now();
|
||||||
|
|
||||||
|
@ -5665,11 +5670,11 @@ fn send_status_update_inner(
|
||||||
.is_ok()
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_branches(
|
async fn update_branches(
|
||||||
state: &Mutex<BackgroundScannerState>,
|
state: &Mutex<BackgroundScannerState>,
|
||||||
repository: &mut LocalRepositoryEntry,
|
repository: &mut LocalRepositoryEntry,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let branches = repository.repo().branches()?;
|
let branches = repository.repo().branches().await?;
|
||||||
let snapshot = state.lock().snapshot.snapshot.clone();
|
let snapshot = state.lock().snapshot.snapshot.clone();
|
||||||
let mut repository = snapshot
|
let mut repository = snapshot
|
||||||
.repository(repository.work_directory.path_key())
|
.repository(repository.work_directory.path_key())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue