git: Check push config before falling back to branch remote (#41700)
Closes #26649 Release Notes: - Improved git support for remotes handling. Git will now check pushRemote and pushDefault configurations before falling back to branch remote. --------- Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
co-authored by
Jakub Konka
parent
d877e562ab
commit
87e3d6e014
@@ -575,7 +575,15 @@ impl GitRepository for FakeGitRepository {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_remotes(&self, _branch: Option<String>) -> BoxFuture<'_, Result<Vec<Remote>>> {
|
||||
fn get_push_remote(&self, _branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_branch_remote(&self, _branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_all_remotes(&self) -> BoxFuture<'_, Result<Vec<Remote>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
@@ -559,7 +559,11 @@ pub trait GitRepository: Send + Sync {
|
||||
cx: AsyncApp,
|
||||
) -> BoxFuture<'_, Result<RemoteCommandOutput>>;
|
||||
|
||||
fn get_remotes(&self, branch_name: Option<String>) -> BoxFuture<'_, Result<Vec<Remote>>>;
|
||||
fn get_push_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>>;
|
||||
|
||||
fn get_branch_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>>;
|
||||
|
||||
fn get_all_remotes(&self) -> BoxFuture<'_, Result<Vec<Remote>>>;
|
||||
|
||||
/// returns a list of remote branches that contain HEAD
|
||||
fn check_for_pushed_commit(&self) -> BoxFuture<'_, Result<Vec<SharedString>>>;
|
||||
@@ -1772,29 +1776,63 @@ impl GitRepository for RealGitRepository {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn get_remotes(&self, branch_name: Option<String>) -> BoxFuture<'_, Result<Vec<Remote>>> {
|
||||
fn get_push_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
|
||||
let working_directory = self.working_directory();
|
||||
let git_binary_path = self.any_git_binary_path.clone();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let working_directory = working_directory?;
|
||||
if let Some(branch_name) = branch_name {
|
||||
let output = new_smol_command(&git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["config", "--get"])
|
||||
.arg(format!("branch.{}.remote", branch_name))
|
||||
.output()
|
||||
.await?;
|
||||
let output = new_smol_command(&git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["rev-parse", "--abbrev-ref"])
|
||||
.arg(format!("{branch}@{{push}}"))
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
return Ok(None);
|
||||
}
|
||||
let remote_name = String::from_utf8_lossy(&output.stdout)
|
||||
.split('/')
|
||||
.next()
|
||||
.map(|name| Remote {
|
||||
name: name.trim().to_string().into(),
|
||||
});
|
||||
|
||||
if output.status.success() {
|
||||
let remote_name = String::from_utf8_lossy(&output.stdout);
|
||||
Ok(remote_name)
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
return Ok(vec![Remote {
|
||||
name: remote_name.trim().to_string().into(),
|
||||
}]);
|
||||
}
|
||||
fn get_branch_remote(&self, branch: String) -> BoxFuture<'_, Result<Option<Remote>>> {
|
||||
let working_directory = self.working_directory();
|
||||
let git_binary_path = self.any_git_binary_path.clone();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let working_directory = working_directory?;
|
||||
let output = new_smol_command(&git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["config", "--get"])
|
||||
.arg(format!("branch.{branch}.remote"))
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let remote_name = String::from_utf8_lossy(&output.stdout);
|
||||
return Ok(Some(Remote {
|
||||
name: remote_name.trim().to_string().into(),
|
||||
}));
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn get_all_remotes(&self) -> BoxFuture<'_, Result<Vec<Remote>>> {
|
||||
let working_directory = self.working_directory();
|
||||
let git_binary_path = self.any_git_binary_path.clone();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let working_directory = working_directory?;
|
||||
let output = new_smol_command(&git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["remote"])
|
||||
@@ -1803,7 +1841,7 @@ impl GitRepository for RealGitRepository {
|
||||
|
||||
anyhow::ensure!(
|
||||
output.status.success(),
|
||||
"Failed to get remotes:\n{}",
|
||||
"Failed to get all remotes:\n{}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
let remote_names = String::from_utf8_lossy(&output.stdout)
|
||||
|
||||
@@ -2111,7 +2111,7 @@ impl GitPanel {
|
||||
cx.spawn_in(window, async move |_, cx| {
|
||||
let repo = repo?;
|
||||
let remotes = repo
|
||||
.update(cx, |repo, _| repo.get_remotes(None))
|
||||
.update(cx, |repo, _| repo.get_remotes(None, false))
|
||||
.ok()?
|
||||
.await
|
||||
.ok()?
|
||||
@@ -2375,7 +2375,7 @@ impl GitPanel {
|
||||
};
|
||||
telemetry::event!("Git Pulled");
|
||||
let branch = branch.clone();
|
||||
let remote = self.get_remote(false, window, cx);
|
||||
let remote = self.get_remote(false, false, window, cx);
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let remote = match remote.await {
|
||||
Ok(Some(remote)) => remote,
|
||||
@@ -2451,7 +2451,7 @@ impl GitPanel {
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let remote = self.get_remote(select_remote, window, cx);
|
||||
let remote = self.get_remote(select_remote, true, window, cx);
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let remote = match remote.await {
|
||||
@@ -2528,6 +2528,7 @@ impl GitPanel {
|
||||
fn get_remote(
|
||||
&mut self,
|
||||
always_select: bool,
|
||||
is_push: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl Future<Output = anyhow::Result<Option<Remote>>> + use<> {
|
||||
@@ -2545,7 +2546,7 @@ impl GitPanel {
|
||||
let current_branch = repo.branch.as_ref().context("No active branch")?;
|
||||
Some(current_branch.name().to_string())
|
||||
};
|
||||
anyhow::Ok(repo.get_remotes(current_branch))
|
||||
anyhow::Ok(repo.get_remotes(current_branch, is_push))
|
||||
})??
|
||||
.await??;
|
||||
|
||||
|
||||
@@ -2096,10 +2096,11 @@ impl GitStore {
|
||||
let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?;
|
||||
|
||||
let branch_name = envelope.payload.branch_name;
|
||||
let is_push = envelope.payload.is_push;
|
||||
|
||||
let remotes = repository_handle
|
||||
.update(&mut cx, |repository_handle, _| {
|
||||
repository_handle.get_remotes(branch_name)
|
||||
repository_handle.get_remotes(branch_name, is_push)
|
||||
})?
|
||||
.await??;
|
||||
|
||||
@@ -4737,12 +4738,26 @@ impl Repository {
|
||||
pub fn get_remotes(
|
||||
&mut self,
|
||||
branch_name: Option<String>,
|
||||
is_push: bool,
|
||||
) -> oneshot::Receiver<Result<Vec<Remote>>> {
|
||||
let id = self.id;
|
||||
self.send_job(None, move |repo, _cx| async move {
|
||||
match repo {
|
||||
RepositoryState::Local(LocalRepositoryState { backend, .. }) => {
|
||||
backend.get_remotes(branch_name).await
|
||||
let remote = if let Some(branch_name) = branch_name {
|
||||
if is_push {
|
||||
backend.get_push_remote(branch_name).await?
|
||||
} else {
|
||||
backend.get_branch_remote(branch_name).await?
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match remote {
|
||||
Some(remote) => Ok(vec![remote]),
|
||||
None => backend.get_all_remotes().await,
|
||||
}
|
||||
}
|
||||
RepositoryState::Remote(RemoteRepositoryState { project_id, client }) => {
|
||||
let response = client
|
||||
@@ -4750,6 +4765,7 @@ impl Repository {
|
||||
project_id: project_id.0,
|
||||
repository_id: id.to_proto(),
|
||||
branch_name,
|
||||
is_push,
|
||||
})
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -389,6 +389,7 @@ message GetRemotes {
|
||||
reserved 2;
|
||||
uint64 repository_id = 3;
|
||||
optional string branch_name = 4;
|
||||
bool is_push = 5;
|
||||
}
|
||||
|
||||
message GetRemotesResponse {
|
||||
|
||||
Reference in New Issue
Block a user