Compare commits
1 Commits
perf/proje
...
git/stagin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a0a9cdb5a |
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user