Improve when the commit suggestions would show (#26313)

Release Notes:

- Git Beta: Fixed a few bugs where the suggested commit text wouldn't
show in certain cases, or would update slowly.
This commit is contained in:
Mikayla Maki 2025-03-07 15:33:48 -08:00 committed by GitHub
parent e70d0edfac
commit f6345a6995
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 180 additions and 89 deletions

View file

@ -54,6 +54,39 @@ impl From<TrackedStatus> for FileStatus {
} }
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum StageStatus {
Staged,
Unstaged,
PartiallyStaged,
}
impl StageStatus {
pub fn is_fully_staged(&self) -> bool {
matches!(self, StageStatus::Staged)
}
pub fn is_fully_unstaged(&self) -> bool {
matches!(self, StageStatus::Unstaged)
}
pub fn has_staged(&self) -> bool {
matches!(self, StageStatus::Staged | StageStatus::PartiallyStaged)
}
pub fn has_unstaged(&self) -> bool {
matches!(self, StageStatus::Unstaged | StageStatus::PartiallyStaged)
}
pub fn as_bool(self) -> Option<bool> {
match self {
StageStatus::Staged => Some(true),
StageStatus::Unstaged => Some(false),
StageStatus::PartiallyStaged => None,
}
}
}
impl FileStatus { impl FileStatus {
pub const fn worktree(worktree_status: StatusCode) -> Self { pub const fn worktree(worktree_status: StatusCode) -> Self {
FileStatus::Tracked(TrackedStatus { FileStatus::Tracked(TrackedStatus {
@ -106,15 +139,15 @@ impl FileStatus {
Ok(status) Ok(status)
} }
pub fn is_staged(self) -> Option<bool> { pub fn staging(self) -> StageStatus {
match self { match self {
FileStatus::Untracked | FileStatus::Ignored | FileStatus::Unmerged { .. } => { FileStatus::Untracked | FileStatus::Ignored | FileStatus::Unmerged { .. } => {
Some(false) StageStatus::Unstaged
} }
FileStatus::Tracked(tracked) => match (tracked.index_status, tracked.worktree_status) { FileStatus::Tracked(tracked) => match (tracked.index_status, tracked.worktree_status) {
(StatusCode::Unmodified, _) => Some(false), (StatusCode::Unmodified, _) => StageStatus::Unstaged,
(_, StatusCode::Unmodified) => Some(true), (_, StatusCode::Unmodified) => StageStatus::Staged,
_ => None, _ => StageStatus::PartiallyStaged,
}, },
} }
} }

View file

@ -22,6 +22,7 @@ use git::repository::{
Branch, CommitDetails, CommitSummary, DiffType, PushOptions, Remote, RemoteCommandOutput, Branch, CommitDetails, CommitSummary, DiffType, PushOptions, Remote, RemoteCommandOutput,
ResetMode, Upstream, UpstreamTracking, UpstreamTrackingStatus, ResetMode, Upstream, UpstreamTracking, UpstreamTrackingStatus,
}; };
use git::status::StageStatus;
use git::{repository::RepoPath, status::FileStatus, Commit, ToggleStaged}; use git::{repository::RepoPath, status::FileStatus, Commit, ToggleStaged};
use git::{ExpandCommitEditor, RestoreTrackedFiles, StageAll, TrashUntrackedFiles, UnstageAll}; use git::{ExpandCommitEditor, RestoreTrackedFiles, StageAll, TrashUntrackedFiles, UnstageAll};
use gpui::{ use gpui::{
@ -195,7 +196,7 @@ pub struct GitStatusEntry {
pub(crate) worktree_path: Arc<Path>, pub(crate) worktree_path: Arc<Path>,
pub(crate) abs_path: PathBuf, pub(crate) abs_path: PathBuf,
pub(crate) status: FileStatus, pub(crate) status: FileStatus,
pub(crate) is_staged: Option<bool>, pub(crate) staging: StageStatus,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -209,7 +210,7 @@ enum TargetStatus {
struct PendingOperation { struct PendingOperation {
finished: bool, finished: bool,
target_status: TargetStatus, target_status: TargetStatus,
repo_paths: HashSet<RepoPath>, entries: Vec<GitStatusEntry>,
op_id: usize, op_id: usize,
} }
@ -226,6 +227,8 @@ pub struct GitPanel {
add_coauthors: bool, add_coauthors: bool,
generate_commit_message_task: Option<Task<Option<()>>>, generate_commit_message_task: Option<Task<Option<()>>>,
entries: Vec<GitListEntry>, entries: Vec<GitListEntry>,
single_staged_entry: Option<GitStatusEntry>,
single_tracked_entry: Option<GitStatusEntry>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
hide_scrollbar_task: Option<Task<()>>, hide_scrollbar_task: Option<Task<()>>,
@ -365,6 +368,8 @@ impl GitPanel {
pending: Vec::new(), pending: Vec::new(),
pending_commit: None, pending_commit: None,
pending_serialization: Task::ready(None), pending_serialization: Task::ready(None),
single_staged_entry: None,
single_tracked_entry: None,
project, project,
scroll_handle, scroll_handle,
scrollbar_state, scrollbar_state,
@ -828,13 +833,13 @@ impl GitPanel {
.repo_path_to_project_path(&entry.repo_path)?; .repo_path_to_project_path(&entry.repo_path)?;
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
if entry.status.is_staged() != Some(false) { if entry.status.staging().has_staged() {
self.perform_stage(false, vec![entry.repo_path.clone()], cx); self.change_file_stage(false, vec![entry.clone()], cx);
} }
let filename = path.path.file_name()?.to_string_lossy(); let filename = path.path.file_name()?.to_string_lossy();
if !entry.status.is_created() { if !entry.status.is_created() {
self.perform_checkout(vec![entry.repo_path.clone()], cx); self.perform_checkout(vec![entry.clone()], cx);
} else { } else {
let prompt = prompt(&format!("Trash {}?", filename), None, window, cx); let prompt = prompt(&format!("Trash {}?", filename), None, window, cx);
cx.spawn_in(window, |_, mut cx| async move { cx.spawn_in(window, |_, mut cx| async move {
@ -863,7 +868,7 @@ impl GitPanel {
}); });
} }
fn perform_checkout(&mut self, repo_paths: Vec<RepoPath>, cx: &mut Context<Self>) { fn perform_checkout(&mut self, entries: Vec<GitStatusEntry>, cx: &mut Context<Self>) {
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
let Some(active_repository) = self.active_repository.clone() else { let Some(active_repository) = self.active_repository.clone() else {
return; return;
@ -873,19 +878,19 @@ impl GitPanel {
self.pending.push(PendingOperation { self.pending.push(PendingOperation {
op_id, op_id,
target_status: TargetStatus::Reverted, target_status: TargetStatus::Reverted,
repo_paths: repo_paths.iter().cloned().collect(), entries: entries.clone(),
finished: false, finished: false,
}); });
self.update_visible_entries(cx); self.update_visible_entries(cx);
let task = cx.spawn(|_, mut cx| async move { let task = cx.spawn(|_, mut cx| async move {
let tasks: Vec<_> = workspace.update(&mut cx, |workspace, cx| { let tasks: Vec<_> = workspace.update(&mut cx, |workspace, cx| {
workspace.project().update(cx, |project, cx| { workspace.project().update(cx, |project, cx| {
repo_paths entries
.iter() .iter()
.filter_map(|repo_path| { .filter_map(|entry| {
let path = active_repository let path = active_repository
.read(cx) .read(cx)
.repo_path_to_project_path(&repo_path)?; .repo_path_to_project_path(&entry.repo_path)?;
Some(project.open_buffer(path, cx)) Some(project.open_buffer(path, cx))
}) })
.collect() .collect()
@ -895,7 +900,15 @@ impl GitPanel {
let buffers = futures::future::join_all(tasks).await; let buffers = futures::future::join_all(tasks).await;
active_repository active_repository
.update(&mut cx, |repo, _| repo.checkout_files("HEAD", repo_paths))? .update(&mut cx, |repo, _| {
repo.checkout_files(
"HEAD",
entries
.iter()
.map(|entries| entries.repo_path.clone())
.collect(),
)
})?
.await??; .await??;
let tasks: Vec<_> = cx.update(|cx| { let tasks: Vec<_> = cx.update(|cx| {
@ -983,8 +996,7 @@ impl GitPanel {
match prompt.await { match prompt.await {
Ok(RestoreCancel::RestoreTrackedFiles) => { Ok(RestoreCancel::RestoreTrackedFiles) => {
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let repo_paths = entries.into_iter().map(|entry| entry.repo_path).collect(); this.perform_checkout(entries, cx);
this.perform_checkout(repo_paths, cx);
}) })
.ok(); .ok();
} }
@ -1053,16 +1065,10 @@ impl GitPanel {
})?; })?;
let to_unstage = to_delete let to_unstage = to_delete
.into_iter() .into_iter()
.filter_map(|entry| { .filter(|entry| !entry.status.staging().is_fully_unstaged())
if entry.status.is_staged() != Some(false) {
Some(entry.repo_path.clone())
} else {
None
}
})
.collect(); .collect();
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.perform_stage(false, to_unstage, cx) this.change_file_stage(false, to_unstage, cx)
})?; })?;
for task in tasks { for task in tasks {
task.await?; task.await?;
@ -1075,25 +1081,25 @@ impl GitPanel {
} }
fn stage_all(&mut self, _: &StageAll, _window: &mut Window, cx: &mut Context<Self>) { fn stage_all(&mut self, _: &StageAll, _window: &mut Window, cx: &mut Context<Self>) {
let repo_paths = self let entries = self
.entries .entries
.iter() .iter()
.filter_map(|entry| entry.status_entry()) .filter_map(|entry| entry.status_entry())
.filter(|status_entry| status_entry.is_staged != Some(true)) .filter(|status_entry| status_entry.staging.has_unstaged())
.map(|status_entry| status_entry.repo_path.clone()) .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.perform_stage(true, repo_paths, cx); self.change_file_stage(true, entries, cx);
} }
fn unstage_all(&mut self, _: &UnstageAll, _window: &mut Window, cx: &mut Context<Self>) { fn unstage_all(&mut self, _: &UnstageAll, _window: &mut Window, cx: &mut Context<Self>) {
let repo_paths = self let entries = self
.entries .entries
.iter() .iter()
.filter_map(|entry| entry.status_entry()) .filter_map(|entry| entry.status_entry())
.filter(|status_entry| status_entry.is_staged != Some(false)) .filter(|status_entry| status_entry.staging.has_staged())
.map(|status_entry| status_entry.repo_path.clone()) .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.perform_stage(false, repo_paths, cx); self.change_file_stage(false, entries, cx);
} }
fn toggle_staged_for_entry( fn toggle_staged_for_entry(
@ -1107,10 +1113,10 @@ impl GitPanel {
}; };
let (stage, repo_paths) = match entry { let (stage, repo_paths) = match entry {
GitListEntry::GitStatusEntry(status_entry) => { GitListEntry::GitStatusEntry(status_entry) => {
if status_entry.status.is_staged().unwrap_or(false) { if status_entry.status.staging().is_fully_staged() {
(false, vec![status_entry.repo_path.clone()]) (false, vec![status_entry.clone()])
} else { } else {
(true, vec![status_entry.repo_path.clone()]) (true, vec![status_entry.clone()])
} }
} }
GitListEntry::Header(section) => { GitListEntry::Header(section) => {
@ -1122,18 +1128,23 @@ impl GitPanel {
.filter_map(|entry| entry.status_entry()) .filter_map(|entry| entry.status_entry())
.filter(|status_entry| { .filter(|status_entry| {
section.contains(&status_entry, repository) section.contains(&status_entry, repository)
&& status_entry.is_staged != Some(goal_staged_state) && status_entry.staging.as_bool() != Some(goal_staged_state)
}) })
.map(|status_entry| status_entry.repo_path.clone()) .map(|status_entry| status_entry.clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(goal_staged_state, entries) (goal_staged_state, entries)
} }
}; };
self.perform_stage(stage, repo_paths, cx); self.change_file_stage(stage, repo_paths, cx);
} }
fn perform_stage(&mut self, stage: bool, repo_paths: Vec<RepoPath>, cx: &mut Context<Self>) { fn change_file_stage(
&mut self,
stage: bool,
entries: Vec<GitStatusEntry>,
cx: &mut Context<Self>,
) {
let Some(active_repository) = self.active_repository.clone() else { let Some(active_repository) = self.active_repository.clone() else {
return; return;
}; };
@ -1145,10 +1156,9 @@ impl GitPanel {
} else { } else {
TargetStatus::Unstaged TargetStatus::Unstaged
}, },
repo_paths: repo_paths.iter().cloned().collect(), entries: entries.clone(),
finished: false, finished: false,
}); });
let repo_paths = repo_paths.clone();
let repository = active_repository.read(cx); let repository = active_repository.read(cx);
self.update_counts(repository); self.update_counts(repository);
cx.notify(); cx.notify();
@ -1158,11 +1168,21 @@ impl GitPanel {
let result = cx let result = cx
.update(|cx| { .update(|cx| {
if stage { if stage {
active_repository active_repository.update(cx, |repo, cx| {
.update(cx, |repo, cx| repo.stage_entries(repo_paths.clone(), cx)) let repo_paths = entries
.iter()
.map(|entry| entry.repo_path.clone())
.collect();
repo.stage_entries(repo_paths, cx)
})
} else { } else {
active_repository active_repository.update(cx, |repo, cx| {
.update(cx, |repo, cx| repo.unstage_entries(repo_paths.clone(), cx)) let repo_paths = entries
.iter()
.map(|entry| entry.repo_path.clone())
.collect();
repo.unstage_entries(repo_paths, cx)
})
} }
})? })?
.await; .await;
@ -1397,21 +1417,13 @@ impl GitPanel {
/// Suggests a commit message based on the changed files and their statuses /// Suggests a commit message based on the changed files and their statuses
pub fn suggest_commit_message(&self) -> Option<String> { pub fn suggest_commit_message(&self) -> Option<String> {
if self.total_staged_count() != 1 { let git_status_entry = if let Some(staged_entry) = &self.single_staged_entry {
return None; Some(staged_entry)
} } else if let Some(single_tracked_entry) = &self.single_tracked_entry {
Some(single_tracked_entry)
let entry = self } else {
.entries None
.iter() }?;
.find(|entry| match entry.status_entry() {
Some(entry) => entry.is_staged.unwrap_or(false),
_ => false,
})?;
let GitListEntry::GitStatusEntry(git_status_entry) = entry.clone() else {
return None;
};
let action_text = if git_status_entry.status.is_deleted() { let action_text = if git_status_entry.status.is_deleted() {
Some("Delete") Some("Delete")
@ -1970,9 +1982,13 @@ impl GitPanel {
fn update_visible_entries(&mut self, cx: &mut Context<Self>) { fn update_visible_entries(&mut self, cx: &mut Context<Self>) {
self.entries.clear(); self.entries.clear();
self.single_staged_entry.take();
self.single_staged_entry.take();
let mut changed_entries = Vec::new(); let mut changed_entries = Vec::new();
let mut new_entries = Vec::new(); let mut new_entries = Vec::new();
let mut conflict_entries = Vec::new(); let mut conflict_entries = Vec::new();
let mut last_staged = None;
let mut staged_count = 0;
let Some(repo) = self.active_repository.as_ref() else { let Some(repo) = self.active_repository.as_ref() else {
// Just clear entries if no repository is active. // Just clear entries if no repository is active.
@ -1985,12 +2001,15 @@ impl GitPanel {
for entry in repo.status() { for entry in repo.status() {
let is_conflict = repo.has_conflict(&entry.repo_path); let is_conflict = repo.has_conflict(&entry.repo_path);
let is_new = entry.status.is_created(); let is_new = entry.status.is_created();
let is_staged = entry.status.is_staged(); let staging = entry.status.staging();
if self.pending.iter().any(|pending| { if self.pending.iter().any(|pending| {
pending.target_status == TargetStatus::Reverted pending.target_status == TargetStatus::Reverted
&& !pending.finished && !pending.finished
&& pending.repo_paths.contains(&entry.repo_path) && pending
.entries
.iter()
.any(|pending| pending.repo_path == entry.repo_path)
}) { }) {
continue; continue;
} }
@ -2007,9 +2026,14 @@ impl GitPanel {
worktree_path, worktree_path,
abs_path, abs_path,
status: entry.status, status: entry.status,
is_staged, staging,
}; };
if staging.has_staged() {
staged_count += 1;
last_staged = Some(entry.clone());
}
if is_conflict { if is_conflict {
conflict_entries.push(entry); conflict_entries.push(entry);
} else if is_new { } else if is_new {
@ -2019,6 +2043,40 @@ impl GitPanel {
} }
} }
let mut pending_staged_count = 0;
let mut last_pending_staged = None;
let mut pending_status_for_last_staged = None;
for pending in self.pending.iter() {
if pending.target_status == TargetStatus::Staged {
pending_staged_count += pending.entries.len();
last_pending_staged = pending.entries.iter().next().cloned();
}
if let Some(last_staged) = &last_staged {
if pending
.entries
.iter()
.any(|entry| entry.repo_path == last_staged.repo_path)
{
pending_status_for_last_staged = Some(pending.target_status);
}
}
}
if conflict_entries.len() == 0 && staged_count == 1 && pending_staged_count == 0 {
match pending_status_for_last_staged {
Some(TargetStatus::Staged) | None => {
self.single_staged_entry = last_staged;
}
_ => {}
}
} else if conflict_entries.len() == 0 && pending_staged_count == 1 {
self.single_staged_entry = last_pending_staged;
}
if conflict_entries.len() == 0 && changed_entries.len() == 1 {
self.single_tracked_entry = changed_entries.first().cloned();
}
if conflict_entries.len() > 0 { if conflict_entries.len() > 0 {
self.entries.push(GitListEntry::Header(GitHeaderEntry { self.entries.push(GitListEntry::Header(GitHeaderEntry {
header: Section::Conflict, header: Section::Conflict,
@ -2083,35 +2141,39 @@ impl GitPanel {
}; };
if repo.has_conflict(&status_entry.repo_path) { if repo.has_conflict(&status_entry.repo_path) {
self.conflicted_count += 1; self.conflicted_count += 1;
if self.entry_is_staged(status_entry) != Some(false) { if self.entry_staging(status_entry).has_staged() {
self.conflicted_staged_count += 1; self.conflicted_staged_count += 1;
} }
} else if status_entry.status.is_created() { } else if status_entry.status.is_created() {
self.new_count += 1; self.new_count += 1;
if self.entry_is_staged(status_entry) != Some(false) { if self.entry_staging(status_entry).has_staged() {
self.new_staged_count += 1; self.new_staged_count += 1;
} }
} else { } else {
self.tracked_count += 1; self.tracked_count += 1;
if self.entry_is_staged(status_entry) != Some(false) { if self.entry_staging(status_entry).has_staged() {
self.tracked_staged_count += 1; self.tracked_staged_count += 1;
} }
} }
} }
} }
fn entry_is_staged(&self, entry: &GitStatusEntry) -> Option<bool> { fn entry_staging(&self, entry: &GitStatusEntry) -> StageStatus {
for pending in self.pending.iter().rev() { for pending in self.pending.iter().rev() {
if pending.repo_paths.contains(&entry.repo_path) { if pending
.entries
.iter()
.any(|pending_entry| pending_entry.repo_path == entry.repo_path)
{
match pending.target_status { match pending.target_status {
TargetStatus::Staged => return Some(true), TargetStatus::Staged => return StageStatus::Staged,
TargetStatus::Unstaged => return Some(false), TargetStatus::Unstaged => return StageStatus::Unstaged,
TargetStatus::Reverted => continue, TargetStatus::Reverted => continue,
TargetStatus::Unchanged => continue, TargetStatus::Unchanged => continue,
} }
} }
} }
entry.is_staged entry.staging
} }
pub(crate) fn has_staged_changes(&self) -> bool { pub(crate) fn has_staged_changes(&self) -> bool {
@ -2604,9 +2666,9 @@ impl GitPanel {
let ix = self.entry_by_path(&repo_path)?; let ix = self.entry_by_path(&repo_path)?;
let entry = self.entries.get(ix)?; let entry = self.entries.get(ix)?;
let is_staged = self.entry_is_staged(entry.status_entry()?); let entry_staging = self.entry_staging(entry.status_entry()?);
let checkbox = Checkbox::new("stage-file", is_staged.into()) let checkbox = Checkbox::new("stage-file", entry_staging.as_bool().into())
.disabled(!self.has_write_access(cx)) .disabled(!self.has_write_access(cx))
.fill() .fill()
.elevation(ElevationIndex::Surface) .elevation(ElevationIndex::Surface)
@ -2752,7 +2814,7 @@ impl GitPanel {
let Some(entry) = self.entries.get(ix).and_then(|e| e.status_entry()) else { let Some(entry) = self.entries.get(ix).and_then(|e| e.status_entry()) else {
return; return;
}; };
let stage_title = if entry.status.is_staged() == Some(true) { let stage_title = if entry.status.staging().is_fully_staged() {
"Unstage File" "Unstage File"
} else { } else {
"Stage File" "Stage File"
@ -2858,8 +2920,8 @@ impl GitPanel {
let checkbox_id: ElementId = let checkbox_id: ElementId =
ElementId::Name(format!("entry_{}_{}_checkbox", display_name, ix).into()); ElementId::Name(format!("entry_{}_{}_checkbox", display_name, ix).into());
let is_entry_staged = self.entry_is_staged(entry); let entry_staging = self.entry_staging(entry);
let mut is_staged: ToggleState = self.entry_is_staged(entry).into(); let mut is_staged: ToggleState = self.entry_staging(entry).as_bool().into();
if !self.has_staged_changes() && !self.has_conflicts() && !entry.status.is_created() { if !self.has_staged_changes() && !self.has_conflicts() && !entry.status.is_created() {
is_staged = ToggleState::Selected; is_staged = ToggleState::Selected;
@ -2978,7 +3040,7 @@ impl GitPanel {
}) })
}) })
.tooltip(move |window, cx| { .tooltip(move |window, cx| {
let tooltip_name = if is_entry_staged.unwrap_or(false) { let tooltip_name = if entry_staging.is_fully_staged() {
"Unstage" "Unstage"
} else { } else {
"Stage" "Stage"
@ -4150,14 +4212,14 @@ mod tests {
repo_path: "crates/gpui/gpui.rs".into(), repo_path: "crates/gpui/gpui.rs".into(),
worktree_path: Path::new("gpui.rs").into(), worktree_path: Path::new("gpui.rs").into(),
status: StatusCode::Modified.worktree(), status: StatusCode::Modified.worktree(),
is_staged: Some(false), staging: StageStatus::Unstaged,
}), }),
GitListEntry::GitStatusEntry(GitStatusEntry { GitListEntry::GitStatusEntry(GitStatusEntry {
abs_path: path!("/root/zed/crates/util/util.rs").into(), abs_path: path!("/root/zed/crates/util/util.rs").into(),
repo_path: "crates/util/util.rs".into(), repo_path: "crates/util/util.rs".into(),
worktree_path: Path::new("../util/util.rs").into(), worktree_path: Path::new("../util/util.rs").into(),
status: StatusCode::Modified.worktree(), status: StatusCode::Modified.worktree(),
is_staged: Some(false), staging: StageStatus::Unstaged,
},), },),
], ],
); );
@ -4224,14 +4286,14 @@ mod tests {
repo_path: "crates/gpui/gpui.rs".into(), repo_path: "crates/gpui/gpui.rs".into(),
worktree_path: Path::new("../../gpui/gpui.rs").into(), worktree_path: Path::new("../../gpui/gpui.rs").into(),
status: StatusCode::Modified.worktree(), status: StatusCode::Modified.worktree(),
is_staged: Some(false), staging: StageStatus::Unstaged,
}), }),
GitListEntry::GitStatusEntry(GitStatusEntry { GitListEntry::GitStatusEntry(GitStatusEntry {
abs_path: path!("/root/zed/crates/util/util.rs").into(), abs_path: path!("/root/zed/crates/util/util.rs").into(),
repo_path: "crates/util/util.rs".into(), repo_path: "crates/util/util.rs".into(),
worktree_path: Path::new("util.rs").into(), worktree_path: Path::new("util.rs").into(),
status: StatusCode::Modified.worktree(), status: StatusCode::Modified.worktree(),
is_staged: Some(false), staging: StageStatus::Unstaged,
},), },),
], ],
); );

View file

@ -1353,7 +1353,7 @@ impl Repository {
let to_stage = self let to_stage = self
.repository_entry .repository_entry
.status() .status()
.filter(|entry| !entry.status.is_staged().unwrap_or(false)) .filter(|entry| !entry.status.staging().is_fully_staged())
.map(|entry| entry.repo_path.clone()) .map(|entry| entry.repo_path.clone())
.collect(); .collect();
self.stage_entries(to_stage, cx) self.stage_entries(to_stage, cx)
@ -1363,7 +1363,7 @@ impl Repository {
let to_unstage = self let to_unstage = self
.repository_entry .repository_entry
.status() .status()
.filter(|entry| entry.status.is_staged().unwrap_or(true)) .filter(|entry| entry.status.staging().has_staged())
.map(|entry| entry.repo_path.clone()) .map(|entry| entry.repo_path.clone())
.collect(); .collect();
self.unstage_entries(to_unstage, cx) self.unstage_entries(to_unstage, cx)

View file

@ -3960,10 +3960,6 @@ pub struct StatusEntry {
} }
impl StatusEntry { impl StatusEntry {
pub fn is_staged(&self) -> Option<bool> {
self.status.is_staged()
}
fn to_proto(&self) -> proto::StatusEntry { fn to_proto(&self) -> proto::StatusEntry {
let simple_status = match self.status { let simple_status = match self.status {
FileStatus::Ignored | FileStatus::Untracked => proto::GitStatus::Added as i32, FileStatus::Ignored | FileStatus::Untracked => proto::GitStatus::Added as i32,