Support git::PullRebase action

Sathiyaraman M created

Change summary

crates/fs/src/fake_git_repo.rs  |  1 
crates/git/src/git.rs           |  2 
crates/git/src/repository.rs    |  3 +
crates/git_ui/src/git_panel.rs  |  3 
crates/git_ui/src/git_ui.rs     | 10 +++
crates/project/src/git_store.rs | 91 ++++++++++++++++++----------------
6 files changed, 66 insertions(+), 44 deletions(-)

Detailed changes

crates/fs/src/fake_git_repo.rs 🔗

@@ -530,6 +530,7 @@ impl GitRepository for FakeGitRepository {
         &self,
         _branch: String,
         _remote: String,
+        _rebase: bool,
         _askpass: AskPassDelegate,
         _env: Arc<HashMap<String, String>>,
         _cx: AsyncApp,

crates/git/src/git.rs 🔗

@@ -72,6 +72,8 @@ actions!(
         ForcePush,
         /// Pulls changes from the remote repository.
         Pull,
+        /// Pulls changes from the remote repository with rebase.
+        PullRebase,
         /// Fetches changes from the remote repository.
         Fetch,
         /// Fetches changes from a specific remote.

crates/git/src/repository.rs 🔗

@@ -480,6 +480,7 @@ pub trait GitRepository: Send + Sync {
         &self,
         branch_name: String,
         upstream_name: String,
+        rebase: bool,
         askpass: AskPassDelegate,
         env: Arc<HashMap<String, String>>,
         // This method takes an AsyncApp to ensure it's invoked on the main thread,
@@ -1578,6 +1579,7 @@ impl GitRepository for RealGitRepository {
         &self,
         branch_name: String,
         remote_name: String,
+        rebase: bool,
         ask_pass: AskPassDelegate,
         env: Arc<HashMap<String, String>>,
         cx: AsyncApp,
@@ -1592,6 +1594,7 @@ impl GitRepository for RealGitRepository {
                 .envs(env.iter())
                 .current_dir(&working_directory?)
                 .args(["pull"])
+                .arg(if rebase { "--rebase" } else { "--no-rebase" })
                 .arg(remote_name)
                 .arg(branch_name)
                 .stdout(smol::process::Stdio::piped())

crates/git_ui/src/git_panel.rs 🔗

@@ -2211,7 +2211,7 @@ impl GitPanel {
         .detach();
     }
 
-    pub(crate) fn pull(&mut self, window: &mut Window, cx: &mut Context<Self>) {
+    pub(crate) fn pull(&mut self, rebase: bool, window: &mut Window, cx: &mut Context<Self>) {
         if !self.can_push_and_pull(cx) {
             return;
         }
@@ -2246,6 +2246,7 @@ impl GitPanel {
                 repo.pull(
                     branch.name().to_owned().into(),
                     remote.name.clone(),
+                    rebase,
                     askpass,
                     cx,
                 )

crates/git_ui/src/git_ui.rs 🔗

@@ -124,7 +124,15 @@ pub fn init(cx: &mut App) {
                     return;
                 };
                 panel.update(cx, |panel, cx| {
-                    panel.pull(window, cx);
+                    panel.pull(false, window, cx);
+                });
+            });
+            workspace.register_action(|workspace, _: &git::PullRebase, window, cx| {
+                let Some(panel) = workspace.panel::<git_panel::GitPanel>(cx) else {
+                    return;
+                };
+                panel.update(cx, |panel, cx| {
+                    panel.pull(true, window, cx);
                 });
             });
         }

crates/project/src/git_store.rs 🔗

@@ -1716,10 +1716,11 @@ impl GitStore {
 
         let branch_name = envelope.payload.branch_name.into();
         let remote_name = envelope.payload.remote_name.into();
+        let rebase = envelope.payload.rebase.into();
 
         let remote_message = repository_handle
             .update(&mut cx, |repository_handle, cx| {
-                repository_handle.pull(branch_name, remote_name, askpass, cx)
+                repository_handle.pull(branch_name, remote_name, rebase, askpass, cx)
             })?
             .await??;
 
@@ -4226,6 +4227,7 @@ impl Repository {
         &mut self,
         branch: SharedString,
         remote: SharedString,
+        rebase: bool,
         askpass: AskPassDelegate,
         _cx: &mut App,
     ) -> oneshot::Receiver<Result<RemoteCommandOutput>> {
@@ -4233,50 +4235,55 @@ impl Repository {
         let askpass_id = util::post_inc(&mut self.latest_askpass_id);
         let id = self.id;
 
-        self.send_job(
-            Some(format!("git pull {} {}", remote, branch).into()),
-            move |git_repo, cx| async move {
-                match git_repo {
-                    RepositoryState::Local {
-                        backend,
-                        environment,
-                        ..
-                    } => {
-                        backend
-                            .pull(
-                                branch.to_string(),
-                                remote.to_string(),
-                                askpass,
-                                environment.clone(),
-                                cx,
-                            )
-                            .await
-                    }
-                    RepositoryState::Remote { project_id, client } => {
-                        askpass_delegates.lock().insert(askpass_id, askpass);
-                        let _defer = util::defer(|| {
-                            let askpass_delegate = askpass_delegates.lock().remove(&askpass_id);
-                            debug_assert!(askpass_delegate.is_some());
-                        });
-                        let response = client
-                            .request(proto::Pull {
-                                project_id: project_id.0,
-                                repository_id: id.to_proto(),
-                                askpass_id,
-                                branch_name: branch.to_string(),
-                                remote_name: remote.to_string(),
-                            })
-                            .await
-                            .context("sending pull request")?;
+        let status = if rebase {
+            Some(format!("git pull --rebase {} {}", remote, branch).into())
+        } else {
+            Some(format!("git pull {} {}", remote, branch).into())
+        };
 
-                        Ok(RemoteCommandOutput {
-                            stdout: response.stdout,
-                            stderr: response.stderr,
+        self.send_job(status, move |git_repo, cx| async move {
+            match git_repo {
+                RepositoryState::Local {
+                    backend,
+                    environment,
+                    ..
+                } => {
+                    backend
+                        .pull(
+                            branch.to_string(),
+                            remote.to_string(),
+                            rebase,
+                            askpass,
+                            environment.clone(),
+                            cx,
+                        )
+                        .await
+                }
+                RepositoryState::Remote { project_id, client } => {
+                    askpass_delegates.lock().insert(askpass_id, askpass);
+                    let _defer = util::defer(|| {
+                        let askpass_delegate = askpass_delegates.lock().remove(&askpass_id);
+                        debug_assert!(askpass_delegate.is_some());
+                    });
+                    let response = client
+                        .request(proto::Pull {
+                            project_id: project_id.0,
+                            repository_id: id.to_proto(),
+                            askpass_id,
+                            rebase,
+                            branch_name: branch.to_string(),
+                            remote_name: remote.to_string(),
                         })
-                    }
+                        .await
+                        .context("sending pull request")?;
+
+                    Ok(RemoteCommandOutput {
+                        stdout: response.stdout,
+                        stderr: response.stderr,
+                    })
                 }
-            },
-        )
+            }
+        })
     }
 
     fn spawn_set_index_text_job(