Compare commits

...

1 Commits

Author SHA1 Message Date
Jakub Konka
5a0a9cdb5a git: Use git::status::StageStatus directly in PendingOps 2025-11-18 11:37:32 +01:00
4 changed files with 123 additions and 156 deletions

View File

@@ -49,7 +49,7 @@ use panel::{
};
use project::{
Fs, Project, ProjectPath,
git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId, pending_op},
git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId},
};
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore, StatusStyle};
@@ -2658,15 +2658,6 @@ impl GitPanel {
let is_new = entry.status.is_created();
let staging = entry.status.staging();
if let Some(pending) = repo.pending_ops_for_path(&entry.repo_path)
&& pending
.ops
.iter()
.any(|op| op.git_status == pending_op::GitStatus::Reverted && op.finished)
{
continue;
}
let entry = GitStatusEntry {
repo_path: entry.repo_path.clone(),
status: entry.status,

View File

@@ -35,8 +35,8 @@ use git::{
},
stash::{GitStash, StashEntry},
status::{
DiffTreeType, FileStatus, GitSummary, StatusCode, TrackedStatus, TreeDiff, TreeDiffStatus,
UnmergedStatus, UnmergedStatusCode,
DiffTreeType, FileStatus, GitSummary, StageStatus, StatusCode, TrackedStatus, TreeDiff,
TreeDiffStatus, UnmergedStatus, UnmergedStatusCode,
},
};
use gpui::{
@@ -48,7 +48,7 @@ use language::{
proto::{deserialize_version, serialize_version},
};
use parking_lot::Mutex;
use pending_op::{PendingOp, PendingOpId, PendingOps};
use pending_op::{PendingOp, PendingOps};
use postage::stream::Stream as _;
use rpc::{
AnyProtoClient, TypedEnvelope,
@@ -3768,47 +3768,39 @@ impl Repository {
let commit = commit.to_string();
let id = self.id;
self.spawn_job_with_tracking(
paths.clone(),
pending_op::GitStatus::Reverted,
cx,
async move |this, cx| {
this.update(cx, |this, _cx| {
this.send_job(
Some(format!("git checkout {}", commit).into()),
move |git_repo, _| async move {
match git_repo {
RepositoryState::Local {
backend,
environment,
..
} => {
backend
.checkout_files(commit, paths, environment.clone())
.await
}
RepositoryState::Remote { project_id, client } => {
client
.request(proto::GitCheckoutFiles {
project_id: project_id.0,
repository_id: id.to_proto(),
commit,
paths: paths
.into_iter()
.map(|p| p.to_proto())
.collect(),
})
.await?;
Ok(())
}
cx.spawn(async move |this, cx| {
this.update(cx, |this, _cx| {
this.send_job(
Some(format!("git checkout {}", commit).into()),
move |git_repo, _| async move {
match git_repo {
RepositoryState::Local {
backend,
environment,
..
} => {
backend
.checkout_files(commit, paths, environment.clone())
.await
}
},
)
})?
.await?
},
)
RepositoryState::Remote { project_id, client } => {
client
.request(proto::GitCheckoutFiles {
project_id: project_id.0,
repository_id: id.to_proto(),
commit,
paths: paths.into_iter().map(|p| p.to_proto()).collect(),
})
.await?;
Ok(())
}
}
},
)
})?
.await?
})
}
pub fn reset(
@@ -3953,9 +3945,9 @@ impl Repository {
let status = format!("git add {paths}");
let job_key = GitJobKey::WriteIndex(entries.clone());
self.spawn_job_with_tracking(
self.spawn_stage_job_with_tracking(
entries.clone(),
pending_op::GitStatus::Staged,
StageStatus::Staged,
cx,
async move |this, cx| {
for save_task in save_tasks {
@@ -4015,9 +4007,9 @@ impl Repository {
let status = format!("git reset {paths}");
let job_key = GitJobKey::WriteIndex(entries.clone());
self.spawn_job_with_tracking(
self.spawn_stage_job_with_tracking(
entries.clone(),
pending_op::GitStatus::Unstaged,
StageStatus::Unstaged,
cx,
async move |this, cx| {
for save_task in save_tasks {
@@ -4059,6 +4051,67 @@ impl Repository {
)
}
fn spawn_stage_job_with_tracking<AsyncFn>(
&mut self,
paths: Vec<RepoPath>,
stage_status: StageStatus,
cx: &mut Context<Self>,
f: AsyncFn,
) -> Task<Result<()>>
where
AsyncFn: AsyncFnOnce(WeakEntity<Repository>, &mut AsyncApp) -> Result<()> + 'static,
{
let mut edits = Vec::with_capacity(paths.len());
let mut ids = Vec::with_capacity(paths.len());
for path in paths {
let mut ops = self
.snapshot
.pending_ops_for_path(&path)
.unwrap_or_else(|| PendingOps::new(&path));
let id = ops.max_id() + 1;
ops.ops.push(PendingOp {
id,
stage_status,
finished: false,
});
edits.push(sum_tree::Edit::Insert(ops));
ids.push((id, path));
}
self.snapshot.pending_ops_by_path.edit(edits, ());
cx.spawn(async move |this, cx| {
let (finished, result) = match f(this.clone(), cx).await {
Ok(()) => (true, Ok(())),
Err(err) if err.is::<Canceled>() => (false, Ok(())),
Err(err) => (false, Err(err)),
};
this.update(cx, |this, _| {
let mut edits = Vec::with_capacity(ids.len());
for (id, entry) in ids {
if let Some(mut ops) = this.snapshot.pending_ops_for_path(&entry) {
if finished {
if let Some(op) = ops.op_by_id_mut(id) {
op.finished = true;
}
} else {
let idx = ops
.ops
.iter()
.position(|op| op.id == id)
.expect("pending operation must exist");
ops.ops.remove(idx);
}
edits.push(sum_tree::Edit::Insert(ops));
}
}
this.snapshot.pending_ops_by_path.edit(edits, ());
})?;
result
})
}
pub fn stage_all(&mut self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> {
let to_stage = self
.cached_status()
@@ -5390,76 +5443,6 @@ impl Repository {
pub fn barrier(&mut self) -> oneshot::Receiver<()> {
self.send_job(None, |_, _| async {})
}
fn spawn_job_with_tracking<AsyncFn>(
&mut self,
paths: Vec<RepoPath>,
git_status: pending_op::GitStatus,
cx: &mut Context<Self>,
f: AsyncFn,
) -> Task<Result<()>>
where
AsyncFn: AsyncFnOnce(WeakEntity<Repository>, &mut AsyncApp) -> Result<()> + 'static,
{
let ids = self.new_pending_ops_for_paths(paths, git_status);
cx.spawn(async move |this, cx| {
let (finished, result) = match f(this.clone(), cx).await {
Ok(()) => (true, Ok(())),
Err(err) if err.is::<Canceled>() => (false, Ok(())),
Err(err) => (false, Err(err)),
};
this.update(cx, |this, _| {
let mut edits = Vec::with_capacity(ids.len());
for (id, entry) in ids {
if let Some(mut ops) = this.snapshot.pending_ops_for_path(&entry) {
if finished {
if let Some(op) = ops.op_by_id_mut(id) {
op.finished = true;
}
} else {
let idx = ops
.ops
.iter()
.position(|op| op.id == id)
.expect("pending operation must exist");
ops.ops.remove(idx);
}
edits.push(sum_tree::Edit::Insert(ops));
}
}
this.snapshot.pending_ops_by_path.edit(edits, ());
})?;
result
})
}
fn new_pending_ops_for_paths(
&mut self,
paths: Vec<RepoPath>,
git_status: pending_op::GitStatus,
) -> Vec<(PendingOpId, RepoPath)> {
let mut edits = Vec::with_capacity(paths.len());
let mut ids = Vec::with_capacity(paths.len());
for path in paths {
let mut ops = self
.snapshot
.pending_ops_for_path(&path)
.unwrap_or_else(|| PendingOps::new(&path));
let id = ops.max_id() + 1;
ops.ops.push(PendingOp {
id,
git_status,
finished: false,
});
edits.push(sum_tree::Edit::Insert(ops));
ids.push((id, path));
}
self.snapshot.pending_ops_by_path.edit(edits, ());
ids
}
}
fn get_permalink_in_rust_registry_src(

View File

@@ -1,16 +1,9 @@
use git::repository::RepoPath;
use git::status::StageStatus;
use std::ops::Add;
use sum_tree::{ContextLessSummary, Item, KeyedItem};
use worktree::{PathKey, PathSummary};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GitStatus {
Staged,
Unstaged,
Reverted,
Unchanged,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PendingOps {
pub repo_path: RepoPath,
@@ -20,7 +13,7 @@ pub struct PendingOps {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PendingOp {
pub id: PendingOpId,
pub git_status: GitStatus,
pub stage_status: StageStatus,
pub finished: bool,
}
@@ -103,20 +96,20 @@ impl PendingOps {
self.ops.iter_mut().find(|op| op.id == id)
}
/// File is staged if the last job is finished and has status Staged.
/// File is staged if the last job is finished and status is fully staged.
pub fn staged(&self) -> bool {
if let Some(last) = self.ops.last() {
if last.git_status == GitStatus::Staged && last.finished {
if last.stage_status.is_fully_staged() && last.finished {
return true;
}
}
false
}
/// File is staged if the last job is not finished and has status Staged.
/// File is staged if the last job is not yet finished and status is fully staged.
pub fn staging(&self) -> bool {
if let Some(last) = self.ops.last() {
if last.git_status == GitStatus::Staged && !last.finished {
if last.stage_status.is_fully_staged() && !last.finished {
return true;
}
}

View File

@@ -17,7 +17,7 @@ use futures::{StreamExt, future};
use git::{
GitHostingProviderRegistry,
repository::{RepoPath, repo_path},
status::{StatusCode, TrackedStatus},
status::{StageStatus, StatusCode, TrackedStatus},
};
use git2::RepositoryInitOptions;
use gpui::{App, BackgroundExecutor, FutureExt, SemanticVersion, UpdateGlobal};
@@ -8614,10 +8614,10 @@ async fn test_repository_pending_ops_staging(
let mut id = 1u16;
let mut assert_stage = async |path: RepoPath, stage| {
let git_status = if stage {
pending_op::GitStatus::Staged
let stage_status = if stage {
StageStatus::Staged
} else {
pending_op::GitStatus::Unstaged
StageStatus::Unstaged
};
repo.update(cx, |repo, cx| {
let task = if stage {
@@ -8630,7 +8630,7 @@ async fn test_repository_pending_ops_staging(
ops.ops.last(),
Some(&pending_op::PendingOp {
id: id.into(),
git_status,
stage_status,
finished: false,
})
);
@@ -8645,7 +8645,7 @@ async fn test_repository_pending_ops_staging(
ops.ops.last(),
Some(&pending_op::PendingOp {
id: id.into(),
git_status,
stage_status,
finished: true,
})
);
@@ -8671,27 +8671,27 @@ async fn test_repository_pending_ops_staging(
vec![
pending_op::PendingOp {
id: 1u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
},
pending_op::PendingOp {
id: 2u16.into(),
git_status: pending_op::GitStatus::Unstaged,
stage_status: StageStatus::Unstaged,
finished: true,
},
pending_op::PendingOp {
id: 3u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
},
pending_op::PendingOp {
id: 4u16.into(),
git_status: pending_op::GitStatus::Unstaged,
stage_status: StageStatus::Unstaged,
finished: true,
},
pending_op::PendingOp {
id: 5u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
}
],
@@ -8791,7 +8791,7 @@ async fn test_repository_pending_ops_long_running_staging(
.ops,
vec![pending_op::PendingOp {
id: 2u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
}],
);
@@ -8893,12 +8893,12 @@ async fn test_repository_pending_ops_stage_all(
vec![
pending_op::PendingOp {
id: 1u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
},
pending_op::PendingOp {
id: 2u16.into(),
git_status: pending_op::GitStatus::Unstaged,
stage_status: StageStatus::Unstaged,
finished: true,
},
],
@@ -8912,12 +8912,12 @@ async fn test_repository_pending_ops_stage_all(
vec![
pending_op::PendingOp {
id: 1u16.into(),
git_status: pending_op::GitStatus::Staged,
stage_status: StageStatus::Staged,
finished: true,
},
pending_op::PendingOp {
id: 2u16.into(),
git_status: pending_op::GitStatus::Unstaged,
stage_status: StageStatus::Unstaged,
finished: true,
},
],