This commit is contained in:
Alvaro Parker 2025-08-08 19:32:11 -04:00
parent 4bee06e507
commit 231a348e69
No known key found for this signature in database
6 changed files with 106 additions and 1 deletions

View file

@ -3,6 +3,7 @@ pub mod commit;
mod hosting_provider;
mod remote;
pub mod repository;
pub mod stash;
pub mod status;
pub use crate::hosting_provider::*;

View file

@ -1,4 +1,5 @@
use crate::commit::parse_git_diff_name_status;
use crate::stash::GitStash;
use crate::status::{GitStatus, StatusCode};
use crate::{Oid, SHORT_SHA_LENGTH};
use anyhow::{Context as _, Result, anyhow, bail};
@ -338,6 +339,8 @@ pub trait GitRepository: Send + Sync {
fn status(&self, path_prefixes: &[RepoPath]) -> Task<Result<GitStatus>>;
fn stash_entries(&self) -> BoxFuture<'_, Result<GitStash>>;
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>>;
fn change_branch(&self, name: String) -> BoxFuture<'_, Result<()>>;
@ -974,6 +977,26 @@ impl GitRepository for RealGitRepository {
})
}
fn stash_entries(&self) -> BoxFuture<'_, Result<GitStash>> {
let git_binary_path = self.git_binary_path.clone();
let working_directory = self.working_directory();
self.executor
.spawn(async move {
let output = new_std_command(&git_binary_path)
.current_dir(working_directory?)
.args(&["stash", "list", "--pretty=%gd:%H:%s"])
.output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
stdout.parse()
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git status failed: {stderr}");
}
})
.boxed()
}
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>> {
let working_directory = self.working_directory();
let git_binary_path = self.git_binary_path.clone();

56
crates/git/src/stash.rs Normal file
View file

@ -0,0 +1,56 @@
use crate::Oid;
use anyhow::Result;
use std::{str::FromStr, sync::Arc};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct StashEntry {
pub index: usize,
pub oid: Oid,
pub message: String,
}
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
pub struct GitStash {
pub entries: Arc<[StashEntry]>,
}
impl FromStr for GitStash {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
// git stash list --pretty=%gd:%H:%s
let entries = s
.split('\n')
.filter_map(|entry| {
let mut parts = entry.splitn(3, ':');
let raw_idx = parts.next().and_then(|i| {
let trimmed = i.trim();
if trimmed.starts_with("stash@{") && trimmed.ends_with('}') {
trimmed
.strip_prefix("stash@{")
.and_then(|s| s.strip_suffix('}'))
} else {
None
}
});
let raw_oid = parts.next();
let message = parts.next();
if let (Some(raw_idx), Some(raw_oid), Some(message)) = (raw_idx, raw_oid, message) {
let index = raw_idx.parse::<usize>().ok()?;
let oid = Oid::from_str(raw_oid).ok()?;
let entry = StashEntry {
index,
oid,
message: message.to_string(),
};
return Some(entry);
}
None
})
.collect::<Arc<[StashEntry]>>();
Ok(Self {
entries: entries.clone(),
})
}
}