From 4b568f4437bd436af3180847fb6a5180c108f076 Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Thu, 7 Aug 2025 13:20:14 -0400 Subject: [PATCH] remote support --- crates/fs/src/fake_git_repo.rs | 12 ++++---- crates/git/src/repository.rs | 6 ++-- crates/git_ui/src/git_ui.rs | 5 +++- crates/project/src/git_store.rs | 50 +++++++++++++++++++++++++++------ crates/proto/proto/git.proto | 4 +-- crates/proto/src/proto.rs | 3 ++ 6 files changed, 60 insertions(+), 20 deletions(-) diff --git a/crates/fs/src/fake_git_repo.rs b/crates/fs/src/fake_git_repo.rs index 02061ecbb70bf8e323981474deb5ac71d6dbad1b..f7f6e160fd33e2ab05dc18082529822fd0b1b5cd 100644 --- a/crates/fs/src/fake_git_repo.rs +++ b/crates/fs/src/fake_git_repo.rs @@ -1,5 +1,5 @@ use crate::{FakeFs, FakeFsEntry, Fs}; -use anyhow::{Context as _, Result}; +use anyhow::{Context as _, Result, bail}; use collections::{HashMap, HashSet}; use futures::future::{self, BoxFuture, join_all}; use git::{ @@ -350,11 +350,13 @@ impl GitRepository for FakeGitRepository { }) } - fn rename_branch(&self, new_name: String) -> BoxFuture<'_, Result<()>> { + fn rename_branch(&self, branch: String, new_name: String) -> BoxFuture<'_, Result<()>> { self.with_state_async(true, move |state| { - if let Some(current_branch) = &state.current_branch_name { - state.branches.insert(new_name.clone()); - state.branches.remove(current_branch); + if !state.branches.remove(&branch) { + bail!("no such branch: {branch}"); + } + state.branches.insert(new_name.clone()); + if state.current_branch_name == Some(branch) { state.current_branch_name = Some(new_name); } Ok(()) diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 468e33152667628a164c1bdb2d0d0d8316d019b3..49578f42d54827d91ebbfc1e2dfb3211d55655eb 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -370,7 +370,7 @@ pub trait GitRepository: Send + Sync { fn change_branch(&self, name: String) -> BoxFuture<'_, Result<()>>; fn create_branch(&self, name: String) -> BoxFuture<'_, Result<()>>; - fn rename_branch(&self, new_name: String) -> BoxFuture<'_, Result<()>>; + fn rename_branch(&self, branch: String, new_name: String) -> BoxFuture<'_, Result<()>>; fn reset( &self, @@ -1131,7 +1131,7 @@ impl GitRepository for RealGitRepository { .boxed() } - fn rename_branch(&self, new_name: String) -> BoxFuture<'_, Result<()>> { + fn rename_branch(&self, branch: String, new_name: String) -> BoxFuture<'_, Result<()>> { let git_binary_path = self.git_binary_path.clone(); let working_directory = self.working_directory(); let executor = self.executor.clone(); @@ -1139,7 +1139,7 @@ impl GitRepository for RealGitRepository { self.executor .spawn(async move { match GitBinary::new(git_binary_path, working_directory?, executor) - .run_with_output(&["branch", "-m", &new_name]) + .run_with_output(&["branch", "-m", &branch, &new_name]) .await { Ok(_) => Ok(()), diff --git a/crates/git_ui/src/git_ui.rs b/crates/git_ui/src/git_ui.rs index f76e6a975e0620e125025a50a4341df999a685a1..7cb5c3818ce9118205febb92ead3fddcd367f3b1 100644 --- a/crates/git_ui/src/git_ui.rs +++ b/crates/git_ui/src/git_ui.rs @@ -276,9 +276,12 @@ impl RenameBranchModal { } let repo = self.repo.clone(); + let current_branch = self.current_branch.to_string(); cx.spawn(async move |_, cx| { match repo - .update(cx, |repo, _| repo.rename_branch(new_name.clone()))? + .update(cx, |repo, _| { + repo.rename_branch(current_branch, new_name.clone()) + })? .await { Ok(Ok(_)) => Ok(()), diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index d294015499a9a3d6e783b081816d94ff6208d8b7..891d74fea63f9000440290209a40cd0a8b1051fe 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -417,6 +417,7 @@ impl GitStore { client.add_entity_request_handler(Self::handle_get_default_branch); client.add_entity_request_handler(Self::handle_change_branch); client.add_entity_request_handler(Self::handle_create_branch); + client.add_entity_request_handler(Self::handle_rename_branch); client.add_entity_request_handler(Self::handle_git_init); client.add_entity_request_handler(Self::handle_push); client.add_entity_request_handler(Self::handle_pull); @@ -1948,6 +1949,25 @@ impl GitStore { Ok(proto::Ack {}) } + async fn handle_rename_branch( + this: Entity, + envelope: TypedEnvelope, + mut cx: AsyncApp, + ) -> Result { + let repository_id = RepositoryId::from_proto(envelope.payload.repository_id); + let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?; + let branch = envelope.payload.branch; + let new_name = envelope.payload.new_name; + + repository_handle + .update(&mut cx, |repository_handle, _| { + repository_handle.rename_branch(branch, new_name) + })? + .await??; + + Ok(proto::Ack {}) + } + async fn handle_show( this: Entity, envelope: TypedEnvelope, @@ -4199,18 +4219,30 @@ impl Repository { ) } - pub fn rename_branch(&mut self, new_name: String) -> oneshot::Receiver> { - let _id = self.id; + pub fn rename_branch( + &mut self, + branch: String, + new_name: String, + ) -> oneshot::Receiver> { + let id = self.id; self.send_job( - Some(format!("git branch -m {new_name}").into()), + Some(format!("git branch -m {branch} {new_name}").into()), move |repo, _cx| async move { match repo { - RepositoryState::Local { backend, .. } => backend.rename_branch(new_name).await, - RepositoryState::Remote { .. } => { - // Remote branch renaming not implemented yet - Err(anyhow::anyhow!( - "Branch renaming is not supported for remote repositories yet" - )) + RepositoryState::Local { backend, .. } => { + backend.rename_branch(branch, new_name).await + } + RepositoryState::Remote { project_id, client } => { + client + .request(proto::GitRenameBranch { + project_id: project_id.0, + repository_id: id.to_proto(), + branch, + new_name, + }) + .await?; + + Ok(()) } } }, diff --git a/crates/proto/proto/git.proto b/crates/proto/proto/git.proto index da6ee61c88d8ea23ce400ccef6ef81242a40e9ae..f63c3e45b0e7ac919300eba2f4d14df141bd2d13 100644 --- a/crates/proto/proto/git.proto +++ b/crates/proto/proto/git.proto @@ -182,8 +182,8 @@ message GitChangeBranch { message GitRenameBranch { uint64 project_id = 1; - reserved 2; - uint64 repository_id = 3; + uint64 repository_id = 2; + string branch = 3; string new_name = 4; } diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index a5dd97661f5a703742278919a2a4bc1831696fde..c764ad712311d254201522a67787911a2b02a2ba 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -301,6 +301,7 @@ messages!( (AskPassResponse, Background), (GitCreateBranch, Background), (GitChangeBranch, Background), + (GitRenameBranch, Background), (CheckForPushedCommits, Background), (CheckForPushedCommitsResponse, Background), (GitDiff, Background), @@ -477,6 +478,7 @@ request_messages!( (AskPassRequest, AskPassResponse), (GitCreateBranch, Ack), (GitChangeBranch, Ack), + (GitRenameBranch, Ack), (CheckForPushedCommits, CheckForPushedCommitsResponse), (GitDiff, GitDiffResponse), (GitInit, Ack), @@ -607,6 +609,7 @@ entity_messages!( Pull, AskPassRequest, GitChangeBranch, + GitRenameBranch, GitCreateBranch, CheckForPushedCommits, GitDiff,