From 07f9d9d9805e2527a792378cdf717e0ce263b935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=80=E1=B4=8D=E1=B4=9B=E1=B4=8F=E1=B4=80=E1=B4=87?= =?UTF-8?q?=CA=80?= Date: Tue, 6 Jan 2026 22:07:22 +0800 Subject: [PATCH] git: Respect upstream branch name when pushing (#46158) Closes #46119 Release Notes: - Fixed git push to respect the upstream branch name instead of defaulting to the local branch name. --- crates/fs/src/fake_git_repo.rs | 1 + crates/git/src/repository.rs | 4 +++- crates/git_ui/src/git_panel.rs | 8 ++++++++ crates/project/src/git_store.rs | 15 +++++++++++++-- crates/proto/proto/git.proto | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/crates/fs/src/fake_git_repo.rs b/crates/fs/src/fake_git_repo.rs index 576eb34341dca78f0a9de2d8ad4ce28e4eaff7db..a83e8197d26d5ca41cc46b998c9e6f65ab8c701f 100644 --- a/crates/fs/src/fake_git_repo.rs +++ b/crates/fs/src/fake_git_repo.rs @@ -597,6 +597,7 @@ impl GitRepository for FakeGitRepository { fn push( &self, _branch: String, + _remote_branch: String, _remote: String, _options: Option, _askpass: AskPassDelegate, diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 17cdbcea27313e911136357ffcde0ca56c19ce67..ca0a0b24d4e33f6e3f977a4451d9dae5ecbddb92 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -573,6 +573,7 @@ pub trait GitRepository: Send + Sync { fn push( &self, branch_name: String, + remote_branch_name: String, upstream_name: String, options: Option, askpass: AskPassDelegate, @@ -1886,6 +1887,7 @@ impl GitRepository for RealGitRepository { fn push( &self, branch_name: String, + remote_branch_name: String, remote_name: String, options: Option, ask_pass: AskPassDelegate, @@ -1910,7 +1912,7 @@ impl GitRepository for RealGitRepository { PushOptions::Force => "--force-with-lease", })) .arg(remote_name) - .arg(format!("{}:{}", branch_name, branch_name)) + .arg(format!("{}:{}", branch_name, remote_branch_name)) .stdin(smol::process::Stdio::null()) .stdout(smol::process::Stdio::piped()) .stderr(smol::process::Stdio::piped()); diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index b832bfbd4b7b6d84ef62688339dba574938bf305..d65fd5c10bc12b9d001a8910da3281a919a1acec 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -3053,6 +3053,14 @@ impl GitPanel { let push = repo.update(cx, |repo, cx| { repo.push( branch.name().to_owned().into(), + branch + .upstream + .as_ref() + .filter(|u| matches!(u.tracking, UpstreamTracking::Tracked(_))) + .and_then(|u| u.branch_name()) + .unwrap_or_else(|| branch.name()) + .to_owned() + .into(), remote.name.clone(), options, askpass_delegate, diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index 751de078d781a70b58801d67b6d137144e66a119..2f0dc3f06bf13ad1f4d455e1a3857fafb02710c6 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -1869,11 +1869,19 @@ impl GitStore { }); let branch_name = envelope.payload.branch_name.into(); + let remote_branch_name = envelope.payload.remote_branch_name.into(); let remote_name = envelope.payload.remote_name.into(); let remote_output = repository_handle .update(&mut cx, |repository_handle, cx| { - repository_handle.push(branch_name, remote_name, options, askpass, cx) + repository_handle.push( + branch_name, + remote_branch_name, + remote_name, + options, + askpass, + cx, + ) })? .await??; Ok(proto::RemoteMessageResponse { @@ -4738,6 +4746,7 @@ impl Repository { pub fn push( &mut self, branch: SharedString, + remote_branch: SharedString, remote: SharedString, options: Option, askpass: AskPassDelegate, @@ -4765,7 +4774,7 @@ impl Repository { let this = cx.weak_entity(); self.send_job( - Some(format!("git push {} {} {}", args, remote, branch).into()), + Some(format!("git push {} {} {}:{}", args, remote, branch, remote_branch).into()), move |git_repo, mut cx| async move { match git_repo { RepositoryState::Local(LocalRepositoryState { @@ -4776,6 +4785,7 @@ impl Repository { let result = backend .push( branch.to_string(), + remote_branch.to_string(), remote.to_string(), options, askpass, @@ -4813,6 +4823,7 @@ impl Repository { repository_id: id.to_proto(), askpass_id, branch_name: branch.to_string(), + remote_branch_name: remote_branch.to_string(), remote_name: remote.to_string(), options: options.map(|options| match options { PushOptions::Force => proto::push::PushOptions::Force, diff --git a/crates/proto/proto/git.proto b/crates/proto/proto/git.proto index d1e56f4f8c89e655dc0e153be013903d48afc99f..29676a3a6f374e2a7e8d80834946560c6a646815 100644 --- a/crates/proto/proto/git.proto +++ b/crates/proto/proto/git.proto @@ -413,6 +413,7 @@ message Push { string branch_name = 5; optional PushOptions options = 6; uint64 askpass_id = 7; + string remote_branch_name = 8; enum PushOptions { SET_UPSTREAM = 0;