Fix git commands for staging and unstaging (#23147)

This fixes a bug that prevents unstaging added files.

I've also removed the batching/debouncing logic in the long-running task
that launches the git invocations---I added this originally but I don't
think it's really necessary.

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-01-14 19:49:07 -05:00 committed by GitHub
parent de6216a02b
commit e86fe1d0b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 111 deletions

View file

@ -54,7 +54,14 @@ pub trait GitRepository: Send + Sync {
/// Returns the path to the repository, typically the `.git` folder.
fn dot_git_dir(&self) -> PathBuf;
fn update_index(&self, stage: &[RepoPath], unstage: &[RepoPath]) -> Result<()>;
/// Updates the index to match the worktree at the given paths.
///
/// If any of the paths have been deleted from the worktree, they will be removed from the index if found there.
fn stage_paths(&self, paths: &[RepoPath]) -> Result<()>;
/// Updates the index to match HEAD at the given paths.
///
/// If any of the paths were previously staged but do not exist in HEAD, they will be removed from the index.
fn unstage_paths(&self, paths: &[RepoPath]) -> Result<()>;
}
impl std::fmt::Debug for dyn GitRepository {
@ -233,31 +240,43 @@ impl GitRepository for RealGitRepository {
)
}
fn update_index(&self, stage: &[RepoPath], unstage: &[RepoPath]) -> Result<()> {
fn stage_paths(&self, paths: &[RepoPath]) -> Result<()> {
let working_directory = self
.repository
.lock()
.workdir()
.context("failed to read git work directory")?
.to_path_buf();
if !stage.is_empty() {
let add = new_std_command(&self.git_binary_path)
if !paths.is_empty() {
let cmd = new_std_command(&self.git_binary_path)
.current_dir(&working_directory)
.args(["add", "--"])
.args(stage.iter().map(|p| p.as_ref()))
.args(["update-index", "--add", "--remove", "--"])
.args(paths.iter().map(|p| p.as_ref()))
.status()?;
if !add.success() {
return Err(anyhow!("Failed to stage files: {add}"));
if !cmd.success() {
return Err(anyhow!("Failed to stage paths: {cmd}"));
}
}
if !unstage.is_empty() {
let rm = new_std_command(&self.git_binary_path)
Ok(())
}
fn unstage_paths(&self, paths: &[RepoPath]) -> Result<()> {
let working_directory = self
.repository
.lock()
.workdir()
.context("failed to read git work directory")?
.to_path_buf();
if !paths.is_empty() {
let cmd = new_std_command(&self.git_binary_path)
.current_dir(&working_directory)
.args(["restore", "--staged", "--"])
.args(unstage.iter().map(|p| p.as_ref()))
.args(["reset", "--quiet", "--"])
.args(paths.iter().map(|p| p.as_ref()))
.status()?;
if !rm.success() {
return Err(anyhow!("Failed to unstage files: {rm}"));
if !cmd.success() {
return Err(anyhow!("Failed to unstage paths: {cmd}"));
}
}
Ok(())
@ -404,7 +423,11 @@ impl GitRepository for FakeGitRepository {
.cloned()
}
fn update_index(&self, _stage: &[RepoPath], _unstage: &[RepoPath]) -> Result<()> {
fn stage_paths(&self, _paths: &[RepoPath]) -> Result<()> {
unimplemented!()
}
fn unstage_paths(&self, _paths: &[RepoPath]) -> Result<()> {
unimplemented!()
}
}