git: Enable git stash in git panel (#32821)

Related discussion #31484

Release Notes:

- Added a menu entry on the git panel to git stash and git pop stash. 

Preview: 


![Screenshot-2025-06-17_08:26:36](https://github.com/user-attachments/assets/d3699ba4-511f-4c7b-a7cc-00a295d01f64)

---------

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Alvaro Parker 2025-07-25 19:15:54 -04:00 committed by GitHub
parent 4d00d07df1
commit 07252c3309
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 290 additions and 2 deletions

View file

@ -420,6 +420,8 @@ impl GitStore {
client.add_entity_request_handler(Self::handle_fetch);
client.add_entity_request_handler(Self::handle_stage);
client.add_entity_request_handler(Self::handle_unstage);
client.add_entity_request_handler(Self::handle_stash);
client.add_entity_request_handler(Self::handle_stash_pop);
client.add_entity_request_handler(Self::handle_commit);
client.add_entity_request_handler(Self::handle_reset);
client.add_entity_request_handler(Self::handle_show);
@ -1696,6 +1698,48 @@ impl GitStore {
Ok(proto::Ack {})
}
async fn handle_stash(
this: Entity<Self>,
envelope: TypedEnvelope<proto::Stash>,
mut cx: AsyncApp,
) -> Result<proto::Ack> {
let repository_id = RepositoryId::from_proto(envelope.payload.repository_id);
let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?;
let entries = envelope
.payload
.paths
.into_iter()
.map(PathBuf::from)
.map(RepoPath::new)
.collect();
repository_handle
.update(&mut cx, |repository_handle, cx| {
repository_handle.stash_entries(entries, cx)
})?
.await?;
Ok(proto::Ack {})
}
async fn handle_stash_pop(
this: Entity<Self>,
envelope: TypedEnvelope<proto::StashPop>,
mut cx: AsyncApp,
) -> Result<proto::Ack> {
let repository_id = RepositoryId::from_proto(envelope.payload.repository_id);
let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?;
repository_handle
.update(&mut cx, |repository_handle, cx| {
repository_handle.stash_pop(cx)
})?
.await?;
Ok(proto::Ack {})
}
async fn handle_set_index_text(
this: Entity<Self>,
envelope: TypedEnvelope<proto::SetIndexText>,
@ -3540,6 +3584,82 @@ impl Repository {
self.unstage_entries(to_unstage, cx)
}
pub fn stash_all(&mut self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> {
let to_stash = self
.cached_status()
.map(|entry| entry.repo_path.clone())
.collect();
self.stash_entries(to_stash, cx)
}
pub fn stash_entries(
&mut self,
entries: Vec<RepoPath>,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<()>> {
let id = self.id;
cx.spawn(async move |this, cx| {
this.update(cx, |this, _| {
this.send_job(None, move |git_repo, _cx| async move {
match git_repo {
RepositoryState::Local {
backend,
environment,
..
} => backend.stash_paths(entries, environment).await,
RepositoryState::Remote { project_id, client } => {
client
.request(proto::Stash {
project_id: project_id.0,
repository_id: id.to_proto(),
paths: entries
.into_iter()
.map(|repo_path| repo_path.as_ref().to_proto())
.collect(),
})
.await
.context("sending stash request")?;
Ok(())
}
}
})
})?
.await??;
Ok(())
})
}
pub fn stash_pop(&mut self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> {
let id = self.id;
cx.spawn(async move |this, cx| {
this.update(cx, |this, _| {
this.send_job(None, move |git_repo, _cx| async move {
match git_repo {
RepositoryState::Local {
backend,
environment,
..
} => backend.stash_pop(environment).await,
RepositoryState::Remote { project_id, client } => {
client
.request(proto::StashPop {
project_id: project_id.0,
repository_id: id.to_proto(),
})
.await
.context("sending stash pop request")?;
Ok(())
}
}
})
})?
.await??;
Ok(())
})
}
pub fn commit(
&mut self,
message: SharedString,